compiler: refactor top-level createInstruction function

Этот коммит содержится в:
Ayke van Laethem 2019-12-09 18:16:45 +01:00 коммит произвёл Ron Evans
родитель c1521fe12e
коммит ad992e2456
2 изменённых файлов: 64 добавлений и 62 удалений

Просмотреть файл

@ -1000,7 +1000,7 @@ func (c *Compiler) parseFunc(frame *Frame) {
fmt.Printf("\t%s\n", instr.String())
}
}
c.parseInstr(frame, instr)
frame.createInstruction(instr)
}
if frame.fn.Name() == "init" && len(block.Instrs) == 0 {
c.builder.CreateRetVoid()
@ -1018,69 +1018,71 @@ func (c *Compiler) parseFunc(frame *Frame) {
}
}
func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
if c.Debug() {
pos := c.ir.Program.Fset.Position(instr.Pos())
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{})
// createInstruction builds the LLVM IR equivalent instructions for the
// particular Go SSA instruction.
func (b *builder) createInstruction(instr ssa.Instruction) {
if b.Debug() {
pos := b.ir.Program.Fset.Position(instr.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
switch instr := instr.(type) {
case ssa.Value:
if value, err := frame.createExpr(instr); err != nil {
if value, err := b.createExpr(instr); err != nil {
// This expression could not be parsed. Add the error to the list
// of diagnostics and continue with an undef value.
// The resulting IR will be incorrect (but valid). However,
// compilation can proceed which is useful because there may be
// more compilation errors which can then all be shown together to
// the user.
c.diagnostics = append(c.diagnostics, err)
frame.locals[instr] = llvm.Undef(c.getLLVMType(instr.Type()))
b.diagnostics = append(b.diagnostics, err)
b.locals[instr] = llvm.Undef(b.getLLVMType(instr.Type()))
} else {
frame.locals[instr] = value
if len(*instr.Referrers()) != 0 && c.NeedsStackObjects() {
c.trackExpr(frame, instr, value)
b.locals[instr] = value
if len(*instr.Referrers()) != 0 && b.NeedsStackObjects() {
b.trackExpr(instr, value)
}
}
case *ssa.DebugRef:
// ignore
case *ssa.Defer:
frame.createDefer(instr)
b.createDefer(instr)
case *ssa.Go:
// Get all function parameters to pass to the goroutine.
var params []llvm.Value
for _, param := range instr.Call.Args {
params = append(params, frame.getValue(param))
params = append(params, b.getValue(param))
}
// Start a new goroutine.
if callee := instr.Call.StaticCallee(); callee != nil {
// Static callee is known. This makes it easier to start a new
// goroutine.
calleeFn := c.ir.GetFunction(callee)
calleeFn := b.ir.GetFunction(callee)
var context llvm.Value
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
context = llvm.Undef(c.i8ptrType)
context = llvm.Undef(b.i8ptrType)
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
funcValue := frame.getValue(value)
context = frame.extractFuncContext(funcValue)
funcValue := b.getValue(value)
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
}
params = append(params, context) // context parameter
frame.createGoInstruction(calleeFn.LLVMFn, params)
b.createGoInstruction(calleeFn.LLVMFn, params)
} else if !instr.Call.IsInvoke() {
// This is a function pointer.
// At the moment, two extra params are passed to the newly started
// goroutine:
// * The function context, for closures.
// * The function pointer (for tasks).
funcPtr, context := frame.decodeFuncValue(frame.getValue(instr.Call.Value), instr.Call.Value.Type().(*types.Signature))
funcPtr, context := b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().(*types.Signature))
params = append(params, context) // context parameter
switch c.Scheduler() {
switch b.Scheduler() {
case "none", "coroutines":
// There are no additional parameters needed for the goroutine start operation.
case "tasks":
@ -1089,58 +1091,58 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
default:
panic("unknown scheduler type")
}
frame.createGoInstruction(funcPtr, params)
b.createGoInstruction(funcPtr, params)
} else {
c.addError(instr.Pos(), "todo: go on interface call")
b.addError(instr.Pos(), "todo: go on interface call")
}
case *ssa.If:
cond := frame.getValue(instr.Cond)
cond := b.getValue(instr.Cond)
block := instr.Block()
blockThen := frame.blockEntries[block.Succs[0]]
blockElse := frame.blockEntries[block.Succs[1]]
c.builder.CreateCondBr(cond, blockThen, blockElse)
blockThen := b.blockEntries[block.Succs[0]]
blockElse := b.blockEntries[block.Succs[1]]
b.CreateCondBr(cond, blockThen, blockElse)
case *ssa.Jump:
blockJump := frame.blockEntries[instr.Block().Succs[0]]
c.builder.CreateBr(blockJump)
blockJump := b.blockEntries[instr.Block().Succs[0]]
b.CreateBr(blockJump)
case *ssa.MapUpdate:
m := frame.getValue(instr.Map)
key := frame.getValue(instr.Key)
value := frame.getValue(instr.Value)
m := b.getValue(instr.Map)
key := b.getValue(instr.Key)
value := b.getValue(instr.Value)
mapType := instr.Map.Type().Underlying().(*types.Map)
frame.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos())
case *ssa.Panic:
value := frame.getValue(instr.X)
c.createRuntimeCall("_panic", []llvm.Value{value}, "")
c.builder.CreateUnreachable()
value := b.getValue(instr.X)
b.createRuntimeCall("_panic", []llvm.Value{value}, "")
b.CreateUnreachable()
case *ssa.Return:
if len(instr.Results) == 0 {
c.builder.CreateRetVoid()
b.CreateRetVoid()
} else if len(instr.Results) == 1 {
c.builder.CreateRet(frame.getValue(instr.Results[0]))
b.CreateRet(b.getValue(instr.Results[0]))
} else {
// Multiple return values. Put them all in a struct.
retVal := llvm.ConstNull(frame.fn.LLVMFn.Type().ElementType().ReturnType())
retVal := llvm.ConstNull(b.fn.LLVMFn.Type().ElementType().ReturnType())
for i, result := range instr.Results {
val := frame.getValue(result)
retVal = c.builder.CreateInsertValue(retVal, val, i, "")
val := b.getValue(result)
retVal = b.CreateInsertValue(retVal, val, i, "")
}
c.builder.CreateRet(retVal)
b.CreateRet(retVal)
}
case *ssa.RunDefers:
frame.createRunDefers()
b.createRunDefers()
case *ssa.Send:
frame.createChanSend(instr)
b.createChanSend(instr)
case *ssa.Store:
llvmAddr := frame.getValue(instr.Addr)
llvmVal := frame.getValue(instr.Val)
frame.createNilCheck(llvmAddr, "store")
if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
llvmAddr := b.getValue(instr.Addr)
llvmVal := b.getValue(instr.Val)
b.createNilCheck(llvmAddr, "store")
if b.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
// nothing to store
return
}
c.builder.CreateStore(llvmVal, llvmAddr)
b.CreateStore(llvmVal, llvmAddr)
default:
c.addError(instr.Pos(), "unknown instruction: "+instr.String())
b.addError(instr.Pos(), "unknown instruction: "+instr.String())
}
}

Просмотреть файл

@ -12,53 +12,53 @@ import (
// trackExpr inserts pointer tracking intrinsics for the GC if the expression is
// one of the expressions that need this.
func (c *Compiler) trackExpr(frame *Frame, expr ssa.Value, value llvm.Value) {
func (b *builder) trackExpr(expr ssa.Value, value llvm.Value) {
// There are uses of this expression, Make sure the pointers
// are tracked during GC.
switch expr := expr.(type) {
case *ssa.Alloc, *ssa.MakeChan, *ssa.MakeMap:
// These values are always of pointer type in IR.
c.trackPointer(value)
b.trackPointer(value)
case *ssa.Call, *ssa.Convert, *ssa.MakeClosure, *ssa.MakeInterface, *ssa.MakeSlice, *ssa.Next:
if !value.IsNil() {
c.trackValue(value)
b.trackValue(value)
}
case *ssa.Select:
if alloca, ok := frame.selectRecvBuf[expr]; ok {
if alloca, ok := b.selectRecvBuf[expr]; ok {
if alloca.IsAUndefValue().IsNil() {
c.trackPointer(alloca)
b.trackPointer(alloca)
}
}
case *ssa.UnOp:
switch expr.Op {
case token.MUL:
// Pointer dereference.
c.trackValue(value)
b.trackValue(value)
case token.ARROW:
// Channel receive operator.
// It's not necessary to look at commaOk here, because in that
// case it's just an aggregate and trackValue will extract the
// pointer in there (if there is one).
c.trackValue(value)
b.trackValue(value)
}
}
}
// trackValue locates pointers in a value (possibly an aggregate) and tracks the
// individual pointers
func (c *Compiler) trackValue(value llvm.Value) {
func (b *builder) trackValue(value llvm.Value) {
typ := value.Type()
switch typ.TypeKind() {
case llvm.PointerTypeKind:
c.trackPointer(value)
b.trackPointer(value)
case llvm.StructTypeKind:
if !typeHasPointers(typ) {
return
}
numElements := typ.StructElementTypesCount()
for i := 0; i < numElements; i++ {
subValue := c.builder.CreateExtractValue(value, i, "")
c.trackValue(subValue)
subValue := b.CreateExtractValue(value, i, "")
b.trackValue(subValue)
}
case llvm.ArrayTypeKind:
if !typeHasPointers(typ) {
@ -66,8 +66,8 @@ func (c *Compiler) trackValue(value llvm.Value) {
}
numElements := typ.ArrayLength()
for i := 0; i < numElements; i++ {
subValue := c.builder.CreateExtractValue(value, i, "")
c.trackValue(subValue)
subValue := b.CreateExtractValue(value, i, "")
b.trackValue(subValue)
}
}
}