compiler: refactor defer operations
Этот коммит содержится в:
родитель
19bf8acde0
коммит
405ec2a563
3 изменённых файлов: 120 добавлений и 111 удалений
|
@ -958,7 +958,7 @@ func (c *Compiler) parseFunc(frame *Frame) {
|
||||||
if frame.fn.Recover != nil {
|
if frame.fn.Recover != nil {
|
||||||
// This function has deferred function calls. Set some things up for
|
// This function has deferred function calls. Set some things up for
|
||||||
// them.
|
// them.
|
||||||
c.deferInitFunc(frame)
|
frame.deferInitFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill blocks with instructions.
|
// Fill blocks with instructions.
|
||||||
|
@ -1044,7 +1044,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
|
||||||
case *ssa.DebugRef:
|
case *ssa.DebugRef:
|
||||||
// ignore
|
// ignore
|
||||||
case *ssa.Defer:
|
case *ssa.Defer:
|
||||||
c.emitDefer(frame, instr)
|
frame.createDefer(instr)
|
||||||
case *ssa.Go:
|
case *ssa.Go:
|
||||||
// Get all function parameters to pass to the goroutine.
|
// Get all function parameters to pass to the goroutine.
|
||||||
var params []llvm.Value
|
var params []llvm.Value
|
||||||
|
@ -1127,7 +1127,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
|
||||||
c.builder.CreateRet(retVal)
|
c.builder.CreateRet(retVal)
|
||||||
}
|
}
|
||||||
case *ssa.RunDefers:
|
case *ssa.RunDefers:
|
||||||
c.emitRunDefers(frame)
|
frame.createRunDefers()
|
||||||
case *ssa.Send:
|
case *ssa.Send:
|
||||||
frame.createChanSend(instr)
|
frame.createChanSend(instr)
|
||||||
case *ssa.Store:
|
case *ssa.Store:
|
||||||
|
|
|
@ -23,16 +23,16 @@ import (
|
||||||
// deferInitFunc sets up this function for future deferred calls. It must be
|
// deferInitFunc sets up this function for future deferred calls. It must be
|
||||||
// called from within the entry block when this function contains deferred
|
// called from within the entry block when this function contains deferred
|
||||||
// calls.
|
// calls.
|
||||||
func (c *Compiler) deferInitFunc(frame *Frame) {
|
func (b *builder) deferInitFunc() {
|
||||||
// Some setup.
|
// Some setup.
|
||||||
frame.deferFuncs = make(map[*ir.Function]int)
|
b.deferFuncs = make(map[*ir.Function]int)
|
||||||
frame.deferInvokeFuncs = make(map[string]int)
|
b.deferInvokeFuncs = make(map[string]int)
|
||||||
frame.deferClosureFuncs = make(map[*ir.Function]int)
|
b.deferClosureFuncs = make(map[*ir.Function]int)
|
||||||
|
|
||||||
// Create defer list pointer.
|
// Create defer list pointer.
|
||||||
deferType := llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0)
|
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
||||||
frame.deferPtr = c.builder.CreateAlloca(deferType, "deferPtr")
|
b.deferPtr = b.CreateAlloca(deferType, "deferPtr")
|
||||||
c.builder.CreateStore(llvm.ConstPointerNull(deferType), frame.deferPtr)
|
b.CreateStore(llvm.ConstPointerNull(deferType), b.deferPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isInLoop checks if there is a path from a basic block to itself.
|
// isInLoop checks if there is a path from a basic block to itself.
|
||||||
|
@ -69,53 +69,53 @@ func isInLoop(start *ssa.BasicBlock) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// emitDefer emits a single defer instruction, to be run when this function
|
// createDefer emits a single defer instruction, to be run when this function
|
||||||
// returns.
|
// returns.
|
||||||
func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) {
|
func (b *builder) createDefer(instr *ssa.Defer) {
|
||||||
// The pointer to the previous defer struct, which we will replace to
|
// The pointer to the previous defer struct, which we will replace to
|
||||||
// make a linked list.
|
// make a linked list.
|
||||||
next := c.builder.CreateLoad(frame.deferPtr, "defer.next")
|
next := b.CreateLoad(b.deferPtr, "defer.next")
|
||||||
|
|
||||||
var values []llvm.Value
|
var values []llvm.Value
|
||||||
valueTypes := []llvm.Type{c.uintptrType, next.Type()}
|
valueTypes := []llvm.Type{b.uintptrType, next.Type()}
|
||||||
if instr.Call.IsInvoke() {
|
if instr.Call.IsInvoke() {
|
||||||
// Method call on an interface.
|
// Method call on an interface.
|
||||||
|
|
||||||
// Get callback type number.
|
// Get callback type number.
|
||||||
methodName := instr.Call.Method.FullName()
|
methodName := instr.Call.Method.FullName()
|
||||||
if _, ok := frame.deferInvokeFuncs[methodName]; !ok {
|
if _, ok := b.deferInvokeFuncs[methodName]; !ok {
|
||||||
frame.deferInvokeFuncs[methodName] = len(frame.allDeferFuncs)
|
b.deferInvokeFuncs[methodName] = len(b.allDeferFuncs)
|
||||||
frame.allDeferFuncs = append(frame.allDeferFuncs, &instr.Call)
|
b.allDeferFuncs = append(b.allDeferFuncs, &instr.Call)
|
||||||
}
|
}
|
||||||
callback := llvm.ConstInt(c.uintptrType, uint64(frame.deferInvokeFuncs[methodName]), false)
|
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferInvokeFuncs[methodName]), false)
|
||||||
|
|
||||||
// Collect all values to be put in the struct (starting with
|
// Collect all values to be put in the struct (starting with
|
||||||
// runtime._defer fields, followed by the call parameters).
|
// runtime._defer fields, followed by the call parameters).
|
||||||
itf := frame.getValue(instr.Call.Value) // interface
|
itf := b.getValue(instr.Call.Value) // interface
|
||||||
receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
||||||
values = []llvm.Value{callback, next, receiverValue}
|
values = []llvm.Value{callback, next, receiverValue}
|
||||||
valueTypes = append(valueTypes, c.i8ptrType)
|
valueTypes = append(valueTypes, b.i8ptrType)
|
||||||
for _, arg := range instr.Call.Args {
|
for _, arg := range instr.Call.Args {
|
||||||
val := frame.getValue(arg)
|
val := b.getValue(arg)
|
||||||
values = append(values, val)
|
values = append(values, val)
|
||||||
valueTypes = append(valueTypes, val.Type())
|
valueTypes = append(valueTypes, val.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if callee, ok := instr.Call.Value.(*ssa.Function); ok {
|
} else if callee, ok := instr.Call.Value.(*ssa.Function); ok {
|
||||||
// Regular function call.
|
// Regular function call.
|
||||||
fn := c.ir.GetFunction(callee)
|
fn := b.ir.GetFunction(callee)
|
||||||
|
|
||||||
if _, ok := frame.deferFuncs[fn]; !ok {
|
if _, ok := b.deferFuncs[fn]; !ok {
|
||||||
frame.deferFuncs[fn] = len(frame.allDeferFuncs)
|
b.deferFuncs[fn] = len(b.allDeferFuncs)
|
||||||
frame.allDeferFuncs = append(frame.allDeferFuncs, fn)
|
b.allDeferFuncs = append(b.allDeferFuncs, fn)
|
||||||
}
|
}
|
||||||
callback := llvm.ConstInt(c.uintptrType, uint64(frame.deferFuncs[fn]), false)
|
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferFuncs[fn]), false)
|
||||||
|
|
||||||
// Collect all values to be put in the struct (starting with
|
// Collect all values to be put in the struct (starting with
|
||||||
// runtime._defer fields).
|
// runtime._defer fields).
|
||||||
values = []llvm.Value{callback, next}
|
values = []llvm.Value{callback, next}
|
||||||
for _, param := range instr.Call.Args {
|
for _, param := range instr.Call.Args {
|
||||||
llvmParam := frame.getValue(param)
|
llvmParam := b.getValue(param)
|
||||||
values = append(values, llvmParam)
|
values = append(values, llvmParam)
|
||||||
valueTypes = append(valueTypes, llvmParam.Type())
|
valueTypes = append(valueTypes, llvmParam.Type())
|
||||||
}
|
}
|
||||||
|
@ -127,23 +127,23 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) {
|
||||||
// pointer.
|
// pointer.
|
||||||
// TODO: ignore this closure entirely and put pointers to the free
|
// TODO: ignore this closure entirely and put pointers to the free
|
||||||
// variables directly in the defer struct, avoiding a memory allocation.
|
// variables directly in the defer struct, avoiding a memory allocation.
|
||||||
closure := frame.getValue(instr.Call.Value)
|
closure := b.getValue(instr.Call.Value)
|
||||||
context := c.builder.CreateExtractValue(closure, 0, "")
|
context := b.CreateExtractValue(closure, 0, "")
|
||||||
|
|
||||||
// Get the callback number.
|
// Get the callback number.
|
||||||
fn := c.ir.GetFunction(makeClosure.Fn.(*ssa.Function))
|
fn := b.ir.GetFunction(makeClosure.Fn.(*ssa.Function))
|
||||||
if _, ok := frame.deferClosureFuncs[fn]; !ok {
|
if _, ok := b.deferClosureFuncs[fn]; !ok {
|
||||||
frame.deferClosureFuncs[fn] = len(frame.allDeferFuncs)
|
b.deferClosureFuncs[fn] = len(b.allDeferFuncs)
|
||||||
frame.allDeferFuncs = append(frame.allDeferFuncs, makeClosure)
|
b.allDeferFuncs = append(b.allDeferFuncs, makeClosure)
|
||||||
}
|
}
|
||||||
callback := llvm.ConstInt(c.uintptrType, uint64(frame.deferClosureFuncs[fn]), false)
|
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferClosureFuncs[fn]), false)
|
||||||
|
|
||||||
// Collect all values to be put in the struct (starting with
|
// Collect all values to be put in the struct (starting with
|
||||||
// runtime._defer fields, followed by all parameters including the
|
// runtime._defer fields, followed by all parameters including the
|
||||||
// context pointer).
|
// context pointer).
|
||||||
values = []llvm.Value{callback, next}
|
values = []llvm.Value{callback, next}
|
||||||
for _, param := range instr.Call.Args {
|
for _, param := range instr.Call.Args {
|
||||||
llvmParam := frame.getValue(param)
|
llvmParam := b.getValue(param)
|
||||||
values = append(values, llvmParam)
|
values = append(values, llvmParam)
|
||||||
valueTypes = append(valueTypes, llvmParam.Type())
|
valueTypes = append(valueTypes, llvmParam.Type())
|
||||||
}
|
}
|
||||||
|
@ -151,41 +151,41 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) {
|
||||||
valueTypes = append(valueTypes, context.Type())
|
valueTypes = append(valueTypes, context.Type())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c.addError(instr.Pos(), "todo: defer on uncommon function call type")
|
b.addError(instr.Pos(), "todo: defer on uncommon function call type")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a struct out of the collected values to put in the defer frame.
|
// Make a struct out of the collected values to put in the defer frame.
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferFrame := llvm.ConstNull(deferFrameType)
|
deferFrame := llvm.ConstNull(deferFrameType)
|
||||||
for i, value := range values {
|
for i, value := range values {
|
||||||
deferFrame = c.builder.CreateInsertValue(deferFrame, value, i, "")
|
deferFrame = b.CreateInsertValue(deferFrame, value, i, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put this struct in an allocation.
|
// Put this struct in an allocation.
|
||||||
var alloca llvm.Value
|
var alloca llvm.Value
|
||||||
if !isInLoop(instr.Block()) {
|
if !isInLoop(instr.Block()) {
|
||||||
// This can safely use a stack allocation.
|
// This can safely use a stack allocation.
|
||||||
alloca = llvmutil.CreateEntryBlockAlloca(c.builder, deferFrameType, "defer.alloca")
|
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferFrameType, "defer.alloca")
|
||||||
} else {
|
} else {
|
||||||
// This may be hit a variable number of times, so use a heap allocation.
|
// This may be hit a variable number of times, so use a heap allocation.
|
||||||
size := c.targetData.TypeAllocSize(deferFrameType)
|
size := b.targetData.TypeAllocSize(deferFrameType)
|
||||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
allocCall := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "defer.alloc.call")
|
allocCall := b.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "defer.alloc.call")
|
||||||
alloca = c.builder.CreateBitCast(allocCall, llvm.PointerType(deferFrameType, 0), "defer.alloc")
|
alloca = b.CreateBitCast(allocCall, llvm.PointerType(deferFrameType, 0), "defer.alloc")
|
||||||
}
|
}
|
||||||
if c.NeedsStackObjects() {
|
if b.NeedsStackObjects() {
|
||||||
c.trackPointer(alloca)
|
b.trackPointer(alloca)
|
||||||
}
|
}
|
||||||
c.builder.CreateStore(deferFrame, alloca)
|
b.CreateStore(deferFrame, alloca)
|
||||||
|
|
||||||
// Push it on top of the linked list by replacing deferPtr.
|
// Push it on top of the linked list by replacing deferPtr.
|
||||||
allocaCast := c.builder.CreateBitCast(alloca, next.Type(), "defer.alloca.cast")
|
allocaCast := b.CreateBitCast(alloca, next.Type(), "defer.alloca.cast")
|
||||||
c.builder.CreateStore(allocaCast, frame.deferPtr)
|
b.CreateStore(allocaCast, b.deferPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// emitRunDefers emits code to run all deferred functions.
|
// createRunDefers emits code to run all deferred functions.
|
||||||
func (c *Compiler) emitRunDefers(frame *Frame) {
|
func (b *builder) createRunDefers() {
|
||||||
// Add a loop like the following:
|
// Add a loop like the following:
|
||||||
// for stack != nil {
|
// for stack != nil {
|
||||||
// _stack := stack
|
// _stack := stack
|
||||||
|
@ -202,44 +202,44 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Create loop.
|
// Create loop.
|
||||||
loophead := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "rundefers.loophead")
|
loophead := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.loophead")
|
||||||
loop := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "rundefers.loop")
|
loop := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.loop")
|
||||||
unreachable := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "rundefers.default")
|
unreachable := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.default")
|
||||||
end := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "rundefers.end")
|
end := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.end")
|
||||||
c.builder.CreateBr(loophead)
|
b.CreateBr(loophead)
|
||||||
|
|
||||||
// Create loop head:
|
// Create loop head:
|
||||||
// for stack != nil {
|
// for stack != nil {
|
||||||
c.builder.SetInsertPointAtEnd(loophead)
|
b.SetInsertPointAtEnd(loophead)
|
||||||
deferData := c.builder.CreateLoad(frame.deferPtr, "")
|
deferData := b.CreateLoad(b.deferPtr, "")
|
||||||
stackIsNil := c.builder.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil")
|
stackIsNil := b.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil")
|
||||||
c.builder.CreateCondBr(stackIsNil, end, loop)
|
b.CreateCondBr(stackIsNil, end, loop)
|
||||||
|
|
||||||
// Create loop body:
|
// Create loop body:
|
||||||
// _stack := stack
|
// _stack := stack
|
||||||
// stack = stack.next
|
// stack = stack.next
|
||||||
// switch stack.callback {
|
// switch stack.callback {
|
||||||
c.builder.SetInsertPointAtEnd(loop)
|
b.SetInsertPointAtEnd(loop)
|
||||||
nextStackGEP := c.builder.CreateInBoundsGEP(deferData, []llvm.Value{
|
nextStackGEP := b.CreateInBoundsGEP(deferData, []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 1, false), // .next field
|
llvm.ConstInt(b.ctx.Int32Type(), 1, false), // .next field
|
||||||
}, "stack.next.gep")
|
}, "stack.next.gep")
|
||||||
nextStack := c.builder.CreateLoad(nextStackGEP, "stack.next")
|
nextStack := b.CreateLoad(nextStackGEP, "stack.next")
|
||||||
c.builder.CreateStore(nextStack, frame.deferPtr)
|
b.CreateStore(nextStack, b.deferPtr)
|
||||||
gep := c.builder.CreateInBoundsGEP(deferData, []llvm.Value{
|
gep := b.CreateInBoundsGEP(deferData, []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false), // .callback field
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false), // .callback field
|
||||||
}, "callback.gep")
|
}, "callback.gep")
|
||||||
callback := c.builder.CreateLoad(gep, "callback")
|
callback := b.CreateLoad(gep, "callback")
|
||||||
sw := c.builder.CreateSwitch(callback, unreachable, len(frame.allDeferFuncs))
|
sw := b.CreateSwitch(callback, unreachable, len(b.allDeferFuncs))
|
||||||
|
|
||||||
for i, callback := range frame.allDeferFuncs {
|
for i, callback := range b.allDeferFuncs {
|
||||||
// Create switch case, for example:
|
// Create switch case, for example:
|
||||||
// case 0:
|
// case 0:
|
||||||
// // run first deferred call
|
// // run first deferred call
|
||||||
block := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "rundefers.callback")
|
block := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.callback")
|
||||||
sw.AddCase(llvm.ConstInt(c.uintptrType, uint64(i), false), block)
|
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
|
||||||
c.builder.SetInsertPointAtEnd(block)
|
b.SetInsertPointAtEnd(block)
|
||||||
switch callback := callback.(type) {
|
switch callback := callback.(type) {
|
||||||
case *ssa.CallCommon:
|
case *ssa.CallCommon:
|
||||||
// Call on an interface value.
|
// Call on an interface value.
|
||||||
|
@ -248,50 +248,50 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0), c.i8ptrType}
|
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0), b.i8ptrType}
|
||||||
for _, arg := range callback.Args {
|
for _, arg := range callback.Args {
|
||||||
valueTypes = append(valueTypes, c.getLLVMType(arg.Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
||||||
}
|
}
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// Extract the params from the struct (including receiver).
|
// Extract the params from the struct (including receiver).
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 2; i < len(valueTypes); i++ {
|
for i := 2; i < len(valueTypes); i++ {
|
||||||
gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
|
||||||
forwardParam := c.builder.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the context parameter. An interface call cannot also be a
|
// Add the context parameter. An interface call cannot also be a
|
||||||
// closure but we have to supply the parameter anyway for platforms
|
// closure but we have to supply the parameter anyway for platforms
|
||||||
// with a strict calling convention.
|
// with a strict calling convention.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||||
|
|
||||||
// Parent coroutine handle.
|
// Parent coroutine handle.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||||
|
|
||||||
fnPtr, _ := frame.getInvokeCall(callback)
|
fnPtr, _ := b.getInvokeCall(callback)
|
||||||
c.createCall(fnPtr, forwardParams, "")
|
b.createCall(fnPtr, forwardParams, "")
|
||||||
|
|
||||||
case *ir.Function:
|
case *ir.Function:
|
||||||
// Direct call.
|
// Direct call.
|
||||||
|
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||||
for _, param := range callback.Params {
|
for _, param := range callback.Params {
|
||||||
valueTypes = append(valueTypes, c.getLLVMType(param.Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(param.Type()))
|
||||||
}
|
}
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// Extract the params from the struct.
|
// Extract the params from the struct.
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := range callback.Params {
|
for i := range callback.Params {
|
||||||
gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||||
forwardParam := c.builder.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,57 +300,57 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
|
||||||
if !callback.IsExported() {
|
if !callback.IsExported() {
|
||||||
// Add the context parameter. We know it is ignored by the receiving
|
// Add the context parameter. We know it is ignored by the receiving
|
||||||
// function, but we have to pass one anyway.
|
// function, but we have to pass one anyway.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||||
|
|
||||||
// Parent coroutine handle.
|
// Parent coroutine handle.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call real function.
|
// Call real function.
|
||||||
c.createCall(callback.LLVMFn, forwardParams, "")
|
b.createCall(callback.LLVMFn, forwardParams, "")
|
||||||
|
|
||||||
case *ssa.MakeClosure:
|
case *ssa.MakeClosure:
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
fn := c.ir.GetFunction(callback.Fn.(*ssa.Function))
|
fn := b.ir.GetFunction(callback.Fn.(*ssa.Function))
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.getLLVMRuntimeType("_defer"), 0)}
|
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||||
params := fn.Signature.Params()
|
params := fn.Signature.Params()
|
||||||
for i := 0; i < params.Len(); i++ {
|
for i := 0; i < params.Len(); i++ {
|
||||||
valueTypes = append(valueTypes, c.getLLVMType(params.At(i).Type()))
|
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||||
}
|
}
|
||||||
valueTypes = append(valueTypes, c.i8ptrType) // closure
|
valueTypes = append(valueTypes, b.i8ptrType) // closure
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
|
||||||
// Extract the params from the struct.
|
// Extract the params from the struct.
|
||||||
forwardParams := []llvm.Value{}
|
forwardParams := []llvm.Value{}
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 2; i < len(valueTypes); i++ {
|
for i := 2; i < len(valueTypes); i++ {
|
||||||
gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "")
|
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
|
||||||
forwardParam := c.builder.CreateLoad(gep, "param")
|
forwardParam := b.CreateLoad(gep, "param")
|
||||||
forwardParams = append(forwardParams, forwardParam)
|
forwardParams = append(forwardParams, forwardParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent coroutine handle.
|
// Parent coroutine handle.
|
||||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||||
|
|
||||||
// Call deferred function.
|
// Call deferred function.
|
||||||
c.createCall(fn.LLVMFn, forwardParams, "")
|
b.createCall(fn.LLVMFn, forwardParams, "")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unknown deferred function type")
|
panic("unknown deferred function type")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branch back to the start of the loop.
|
// Branch back to the start of the loop.
|
||||||
c.builder.CreateBr(loophead)
|
b.CreateBr(loophead)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create default unreachable block:
|
// Create default unreachable block:
|
||||||
// default:
|
// default:
|
||||||
// unreachable
|
// unreachable
|
||||||
// }
|
// }
|
||||||
c.builder.SetInsertPointAtEnd(unreachable)
|
b.SetInsertPointAtEnd(unreachable)
|
||||||
c.builder.CreateUnreachable()
|
b.CreateUnreachable()
|
||||||
|
|
||||||
// End of loop.
|
// End of loop.
|
||||||
c.builder.SetInsertPointAtEnd(end)
|
b.SetInsertPointAtEnd(end)
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,15 @@ func (c *Compiler) trackPointer(value llvm.Value) {
|
||||||
c.createRuntimeCall("trackPointer", []llvm.Value{value}, "")
|
c.createRuntimeCall("trackPointer", []llvm.Value{value}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trackPointer creates a call to runtime.trackPointer, bitcasting the poitner
|
||||||
|
// first if needed. The input value must be of LLVM pointer type.
|
||||||
|
func (b *builder) trackPointer(value llvm.Value) {
|
||||||
|
if value.Type() != b.i8ptrType {
|
||||||
|
value = b.CreateBitCast(value, b.i8ptrType, "")
|
||||||
|
}
|
||||||
|
b.createRuntimeCall("trackPointer", []llvm.Value{value}, "")
|
||||||
|
}
|
||||||
|
|
||||||
// typeHasPointers returns whether this type is a pointer or contains pointers.
|
// typeHasPointers returns whether this type is a pointer or contains pointers.
|
||||||
// If the type is an aggregate type, it will check whether there is a pointer
|
// If the type is an aggregate type, it will check whether there is a pointer
|
||||||
// inside.
|
// inside.
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче