compiler: refactor defer operations

Этот коммит содержится в:
Ayke van Laethem 2019-11-24 12:43:43 +01:00 коммит произвёл Ron Evans
родитель 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.