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