This commit adds getValue which gets a const, global, or result of a
local SSA expression and replaces (almost) all uses of parseExpr with
getValue. The only remaining use is in parseInstr, which makes sure an
instruction is only evaluated once.
Этот коммит содержится в:
Ayke van Laethem 2019-04-21 15:39:27 +02:00 коммит произвёл Ron Evans
родитель c25fe609a9
коммит 45cacda7b3
7 изменённых файлов: 158 добавлений и 359 удалений

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

@ -29,33 +29,23 @@ func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
// emitChanSend emits a pseudo chan send operation. It is lowered to the actual // emitChanSend emits a pseudo chan send operation. It is lowered to the actual
// channel send operation during goroutine lowering. // channel send operation during goroutine lowering.
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error { func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) {
valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem()) valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
ch, err := c.parseExpr(frame, instr.Chan) ch := c.getValue(frame, instr.Chan)
if err != nil { chanValue := c.getValue(frame, instr.X)
return err
}
chanValue, err := c.parseExpr(frame, instr.X)
if err != nil {
return err
}
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value") valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
c.builder.CreateStore(chanValue, valueAlloca) c.builder.CreateStore(chanValue, valueAlloca)
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr") valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
c.createRuntimeCall("chanSendStub", []llvm.Value{llvm.Undef(c.i8ptrType), ch, valueAllocaCast, valueSize}, "") c.createRuntimeCall("chanSendStub", []llvm.Value{llvm.Undef(c.i8ptrType), ch, valueAllocaCast, valueSize}, "")
return nil
} }
// emitChanRecv emits a pseudo chan receive operation. It is lowered to the // emitChanRecv emits a pseudo chan receive operation. It is lowered to the
// actual channel receive operation during goroutine lowering. // actual channel receive operation during goroutine lowering.
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value {
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem()) valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
ch, err := c.parseExpr(frame, unop.X) ch := c.getValue(frame, unop.X)
if err != nil {
return llvm.Value{}, err
}
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value") valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr") valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
valueOk := c.builder.CreateAlloca(c.ctx.Int1Type(), "chan.comma-ok.alloca") valueOk := c.builder.CreateAlloca(c.ctx.Int1Type(), "chan.comma-ok.alloca")
@ -66,20 +56,16 @@ func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{valueType, c.ctx.Int1Type()}, false)) tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{valueType, c.ctx.Int1Type()}, false))
tuple = c.builder.CreateInsertValue(tuple, received, 0, "") tuple = c.builder.CreateInsertValue(tuple, received, 0, "")
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "")
return tuple, nil return tuple
} else { } else {
return received, nil return received
} }
} }
// emitChanClose closes the given channel. // emitChanClose closes the given channel.
func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) error { func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) {
valueType := c.getLLVMType(param.Type().(*types.Chan).Elem()) valueType := c.getLLVMType(param.Type().(*types.Chan).Elem())
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
ch, err := c.parseExpr(frame, param) ch := c.getValue(frame, param)
if err != nil {
return err
}
c.createRuntimeCall("chanClose", []llvm.Value{ch, valueSize}, "") c.createRuntimeCall("chanClose", []llvm.Value{ch, valueSize}, "")
return nil
} }

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

@ -818,10 +818,7 @@ func (c *Compiler) parseFunc(frame *Frame) error {
for _, phi := range frame.phis { for _, phi := range frame.phis {
block := phi.ssa.Block() block := phi.ssa.Block()
for i, edge := range phi.ssa.Edges { for i, edge := range phi.ssa.Edges {
llvmVal, err := c.parseExpr(frame, edge) llvmVal := c.getValue(frame, edge)
if err != nil {
return err
}
llvmBlock := frame.blockExits[block.Preds[i]] llvmBlock := frame.blockExits[block.Preds[i]]
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock}) phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
} }
@ -866,11 +863,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
// 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
for _, param := range instr.Call.Args { for _, param := range instr.Call.Args {
val, err := c.parseExpr(frame, param) params = append(params, c.getValue(frame, param))
if err != nil {
return err
}
params = append(params, val)
} }
if !calleeFn.IsExported() { if !calleeFn.IsExported() {
params = append(params, llvm.Undef(c.i8ptrType)) // context parameter params = append(params, llvm.Undef(c.i8ptrType)) // context parameter
@ -880,10 +873,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
c.createCall(calleeValue, params, "") c.createCall(calleeValue, params, "")
return nil return nil
case *ssa.If: case *ssa.If:
cond, err := c.parseExpr(frame, instr.Cond) cond := c.getValue(frame, instr.Cond)
if err != nil {
return err
}
block := instr.Block() block := instr.Block()
blockThen := frame.blockEntries[block.Succs[0]] blockThen := frame.blockEntries[block.Succs[0]]
blockElse := frame.blockEntries[block.Succs[1]] blockElse := frame.blockEntries[block.Succs[1]]
@ -894,25 +884,13 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
c.builder.CreateBr(blockJump) c.builder.CreateBr(blockJump)
return nil return nil
case *ssa.MapUpdate: case *ssa.MapUpdate:
m, err := c.parseExpr(frame, instr.Map) m := c.getValue(frame, instr.Map)
if err != nil { key := c.getValue(frame, instr.Key)
return err value := c.getValue(frame, instr.Value)
}
key, err := c.parseExpr(frame, instr.Key)
if err != nil {
return err
}
value, err := c.parseExpr(frame, instr.Value)
if err != nil {
return err
}
mapType := instr.Map.Type().Underlying().(*types.Map) mapType := instr.Map.Type().Underlying().(*types.Map)
return c.emitMapUpdate(mapType.Key(), m, key, value, instr.Pos()) return c.emitMapUpdate(mapType.Key(), m, key, value, instr.Pos())
case *ssa.Panic: case *ssa.Panic:
value, err := c.parseExpr(frame, instr.X) value := c.getValue(frame, instr.X)
if err != nil {
return err
}
c.createRuntimeCall("_panic", []llvm.Value{value}, "") c.createRuntimeCall("_panic", []llvm.Value{value}, "")
c.builder.CreateUnreachable() c.builder.CreateUnreachable()
return nil return nil
@ -921,20 +899,13 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
c.builder.CreateRetVoid() c.builder.CreateRetVoid()
return nil return nil
} else if len(instr.Results) == 1 { } else if len(instr.Results) == 1 {
val, err := c.parseExpr(frame, instr.Results[0]) c.builder.CreateRet(c.getValue(frame, instr.Results[0]))
if err != nil {
return err
}
c.builder.CreateRet(val)
return nil return nil
} else { } else {
// Multiple return values. Put them all in a struct. // Multiple return values. Put them all in a struct.
retVal := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType()) retVal := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType())
for i, result := range instr.Results { for i, result := range instr.Results {
val, err := c.parseExpr(frame, result) val := c.getValue(frame, result)
if err != nil {
return err
}
retVal = c.builder.CreateInsertValue(retVal, val, i, "") retVal = c.builder.CreateInsertValue(retVal, val, i, "")
} }
c.builder.CreateRet(retVal) c.builder.CreateRet(retVal)
@ -943,16 +914,11 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
case *ssa.RunDefers: case *ssa.RunDefers:
return c.emitRunDefers(frame) return c.emitRunDefers(frame)
case *ssa.Send: case *ssa.Send:
return c.emitChanSend(frame, instr) c.emitChanSend(frame, instr)
return nil
case *ssa.Store: case *ssa.Store:
llvmAddr, err := c.parseExpr(frame, instr.Addr) llvmAddr := c.getValue(frame, instr.Addr)
if err != nil { llvmVal := c.getValue(frame, instr.Val)
return err
}
llvmVal, err := c.parseExpr(frame, instr.Val)
if err != nil {
return err
}
if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 { if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
// nothing to store // nothing to store
return nil return nil
@ -972,14 +938,8 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, pos token.Pos) (llvm.Value, error) { func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, pos token.Pos) (llvm.Value, error) {
switch callName { switch callName {
case "append": case "append":
src, err := c.parseExpr(frame, args[0]) src := c.getValue(frame, args[0])
if err != nil { elems := c.getValue(frame, args[1])
return llvm.Value{}, err
}
elems, err := c.parseExpr(frame, args[1])
if err != nil {
return llvm.Value{}, err
}
srcBuf := c.builder.CreateExtractValue(src, 0, "append.srcBuf") srcBuf := c.builder.CreateExtractValue(src, 0, "append.srcBuf")
srcPtr := c.builder.CreateBitCast(srcBuf, c.i8ptrType, "append.srcPtr") srcPtr := c.builder.CreateBitCast(srcBuf, c.i8ptrType, "append.srcPtr")
srcLen := c.builder.CreateExtractValue(src, 1, "append.srcLen") srcLen := c.builder.CreateExtractValue(src, 1, "append.srcLen")
@ -1000,10 +960,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
newSlice = c.builder.CreateInsertValue(newSlice, newCap, 2, "") newSlice = c.builder.CreateInsertValue(newSlice, newCap, 2, "")
return newSlice, nil return newSlice, nil
case "cap": case "cap":
value, err := c.parseExpr(frame, args[0]) value := c.getValue(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
var llvmCap llvm.Value var llvmCap llvm.Value
switch args[0].Type().(type) { switch args[0].Type().(type) {
case *types.Chan: case *types.Chan:
@ -1020,16 +977,11 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
} }
return llvmCap, nil return llvmCap, nil
case "close": case "close":
return llvm.Value{}, c.emitChanClose(frame, args[0]) c.emitChanClose(frame, args[0])
return llvm.Value{}, nil
case "complex": case "complex":
r, err := c.parseExpr(frame, args[0]) r := c.getValue(frame, args[0])
if err != nil { i := c.getValue(frame, args[1])
return llvm.Value{}, err
}
i, err := c.parseExpr(frame, args[1])
if err != nil {
return llvm.Value{}, err
}
t := args[0].Type().Underlying().(*types.Basic) t := args[0].Type().Underlying().(*types.Basic)
var cplx llvm.Value var cplx llvm.Value
switch t.Kind() { switch t.Kind() {
@ -1044,14 +996,8 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
cplx = c.builder.CreateInsertValue(cplx, i, 1, "") cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil return cplx, nil
case "copy": case "copy":
dst, err := c.parseExpr(frame, args[0]) dst := c.getValue(frame, args[0])
if err != nil { src := c.getValue(frame, args[1])
return llvm.Value{}, err
}
src, err := c.parseExpr(frame, args[1])
if err != nil {
return llvm.Value{}, err
}
dstLen := c.builder.CreateExtractValue(dst, 1, "copy.dstLen") dstLen := c.builder.CreateExtractValue(dst, 1, "copy.dstLen")
srcLen := c.builder.CreateExtractValue(src, 1, "copy.srcLen") srcLen := c.builder.CreateExtractValue(src, 1, "copy.srcLen")
dstBuf := c.builder.CreateExtractValue(dst, 0, "copy.dstArray") dstBuf := c.builder.CreateExtractValue(dst, 0, "copy.dstArray")
@ -1062,26 +1008,14 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
elemSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(elemType), false) elemSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(elemType), false)
return c.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil return c.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
case "delete": case "delete":
m, err := c.parseExpr(frame, args[0]) m := c.getValue(frame, args[0])
if err != nil { key := c.getValue(frame, args[1])
return llvm.Value{}, err
}
key, err := c.parseExpr(frame, args[1])
if err != nil {
return llvm.Value{}, err
}
return llvm.Value{}, c.emitMapDelete(args[1].Type(), m, key, pos) return llvm.Value{}, c.emitMapDelete(args[1].Type(), m, key, pos)
case "imag": case "imag":
cplx, err := c.parseExpr(frame, args[0]) cplx := c.getValue(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
return c.builder.CreateExtractValue(cplx, 1, "imag"), nil return c.builder.CreateExtractValue(cplx, 1, "imag"), nil
case "len": case "len":
value, err := c.parseExpr(frame, args[0]) value := c.getValue(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
var llvmLen llvm.Value var llvmLen llvm.Value
switch args[0].Type().Underlying().(type) { switch args[0].Type().Underlying().(type) {
case *types.Basic, *types.Slice: case *types.Basic, *types.Slice:
@ -1105,10 +1039,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
if i >= 1 && callName == "println" { if i >= 1 && callName == "println" {
c.createRuntimeCall("printspace", nil, "") c.createRuntimeCall("printspace", nil, "")
} }
value, err := c.parseExpr(frame, arg) value := c.getValue(frame, arg)
if err != nil {
return llvm.Value{}, err
}
typ := arg.Type().Underlying() typ := arg.Type().Underlying()
switch typ := typ.(type) { switch typ := typ.(type) {
case *types.Basic: case *types.Basic:
@ -1161,29 +1092,22 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
} }
return llvm.Value{}, nil // print() or println() returns void return llvm.Value{}, nil // print() or println() returns void
case "real": case "real":
cplx, err := c.parseExpr(frame, args[0]) cplx := c.getValue(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
return c.builder.CreateExtractValue(cplx, 0, "real"), nil return c.builder.CreateExtractValue(cplx, 0, "real"), nil
case "recover": case "recover":
return c.createRuntimeCall("_recover", nil, ""), nil return c.createRuntimeCall("_recover", nil, ""), nil
case "ssa:wrapnilchk": case "ssa:wrapnilchk":
// TODO: do an actual nil check? // TODO: do an actual nil check?
return c.parseExpr(frame, args[0]) return c.getValue(frame, args[0]), nil
default: default:
return llvm.Value{}, c.makeError(pos, "todo: builtin: "+callName) return llvm.Value{}, c.makeError(pos, "todo: builtin: "+callName)
} }
} }
func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, context llvm.Value, exported bool) (llvm.Value, error) { func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, context llvm.Value, exported bool) llvm.Value {
var params []llvm.Value var params []llvm.Value
for _, param := range args { for _, param := range args {
val, err := c.parseExpr(frame, param) params = append(params, c.getValue(frame, param))
if err != nil {
return llvm.Value{}, err
}
params = append(params, val)
} }
if !exported { if !exported {
@ -1195,15 +1119,12 @@ func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, con
params = append(params, llvm.Undef(c.i8ptrType)) params = append(params, llvm.Undef(c.i8ptrType))
} }
return c.createCall(llvmFn, params, ""), nil return c.createCall(llvmFn, params, "")
} }
func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) { func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) {
if instr.IsInvoke() { if instr.IsInvoke() {
fnCast, args, err := c.getInvokeCall(frame, instr) fnCast, args := c.getInvokeCall(frame, instr)
if err != nil {
return llvm.Value{}, err
}
return c.createCall(fnCast, args, ""), nil return c.createCall(fnCast, args, ""), nil
} }
@ -1234,15 +1155,12 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
case *ssa.MakeClosure: case *ssa.MakeClosure:
// A call on a func value, but the callee is trivial to find. For // A call on a func value, but the callee is trivial to find. For
// example: immediately applied functions. // example: immediately applied functions.
funcValue, err := c.parseExpr(frame, value) funcValue := c.getValue(frame, value)
if err != nil {
return llvm.Value{}, err
}
context = c.extractFuncContext(funcValue) context = c.extractFuncContext(funcValue)
default: default:
panic("StaticCallee returned an unexpected value") panic("StaticCallee returned an unexpected value")
} }
return c.parseFunctionCall(frame, instr.Args, targetFunc.LLVMFn, context, targetFunc.IsExported()) return c.parseFunctionCall(frame, instr.Args, targetFunc.LLVMFn, context, targetFunc.IsExported()), nil
} }
// Builtin or function pointer. // Builtin or function pointer.
@ -1250,10 +1168,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
case *ssa.Builtin: case *ssa.Builtin:
return c.parseBuiltin(frame, instr.Args, call.Name(), instr.Pos()) return c.parseBuiltin(frame, instr.Args, call.Name(), instr.Pos())
default: // function pointer default: // function pointer
value, err := c.parseExpr(frame, instr.Value) value := c.getValue(frame, instr.Value)
if err != nil {
return llvm.Value{}, err
}
// This is a func value, which cannot be called directly. We have to // This is a func value, which cannot be called directly. We have to
// extract the function pointer and context first from the func value. // extract the function pointer and context first from the func value.
funcPtr, context, err := c.decodeFuncValue(value, instr.Value.Type().(*types.Signature)) funcPtr, context, err := c.decodeFuncValue(value, instr.Value.Type().(*types.Signature))
@ -1261,17 +1176,46 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
return llvm.Value{}, err return llvm.Value{}, err
} }
c.emitNilCheck(frame, funcPtr, "fpcall") c.emitNilCheck(frame, funcPtr, "fpcall")
return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false) return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false), nil
} }
} }
func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { // getValue returns the LLVM value of a constant, function value, global, or
if value, ok := frame.locals[expr]; ok { // already processed SSA expression.
// Value is a local variable that has already been computed. func (c *Compiler) getValue(frame *Frame, expr ssa.Value) llvm.Value {
if value.IsNil() { switch expr := expr.(type) {
return llvm.Value{}, c.makeError(expr.Pos(), "undefined local var (from cgo?)") case *ssa.Const:
return c.parseConst(frame.fn.LinkName(), expr)
case *ssa.Function:
fn := c.ir.GetFunction(expr)
if fn.IsExported() {
// TODO: report this as a compiler diagnostic
panic("cannot use an exported function as value: " + expr.String())
} }
return value, nil return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature)
case *ssa.Global:
value := c.ir.GetGlobal(expr).LLVMGlobal
if value.IsNil() {
// TODO: report this as a compiler diagnostic
panic("global not found: " + c.ir.GetGlobal(expr).LinkName())
}
return value
default:
// other (local) SSA value
if value, ok := frame.locals[expr]; ok {
return value
} else {
// indicates a compiler bug
panic("local has not been parsed: " + expr.String())
}
}
}
// parseExpr translates a Go SSA expression to a LLVM instruction.
func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
if _, ok := frame.locals[expr]; ok {
// sanity check
panic("local has already been parsed: " + expr.String())
} }
switch expr := expr.(type) { switch expr := expr.(type) {
@ -1298,14 +1242,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} }
return buf, nil return buf, nil
case *ssa.BinOp: case *ssa.BinOp:
x, err := c.parseExpr(frame, expr.X) x := c.getValue(frame, expr.X)
if err != nil { y := c.getValue(frame, expr.Y)
return llvm.Value{}, err
}
y, err := c.parseExpr(frame, expr.Y)
if err != nil {
return llvm.Value{}, err
}
return c.parseBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos()) return c.parseBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos())
case *ssa.Call: case *ssa.Call:
// Passing the current task here to the subroutine. It is only used when // Passing the current task here to the subroutine. It is only used when
@ -1318,15 +1256,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// This is different from how the official Go compiler works, because of // This is different from how the official Go compiler works, because of
// heap allocation and because it's easier to implement, see: // heap allocation and because it's easier to implement, see:
// https://research.swtch.com/interfaces // https://research.swtch.com/interfaces
return c.parseExpr(frame, expr.X) return c.getValue(frame, expr.X), nil
case *ssa.ChangeType: case *ssa.ChangeType:
// This instruction changes the type, but the underlying value remains // This instruction changes the type, but the underlying value remains
// the same. This is often a no-op, but sometimes we have to change the // the same. This is often a no-op, but sometimes we have to change the
// LLVM type as well. // LLVM type as well.
x, err := c.parseExpr(frame, expr.X) x := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
llvmType := c.getLLVMType(expr.Type()) llvmType := c.getLLVMType(expr.Type())
if x.Type() == llvmType { if x.Type() == llvmType {
// Different Go type but same LLVM type (for example, named int). // Different Go type but same LLVM type (for example, named int).
@ -1353,25 +1288,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String()) return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
} }
case *ssa.Const: case *ssa.Const:
return c.parseConst(frame.fn.LinkName(), expr) panic("const is not an expression")
case *ssa.Convert: case *ssa.Convert:
x, err := c.parseExpr(frame, expr.X) x := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
return c.parseConvert(expr.X.Type(), expr.Type(), x, expr.Pos()) return c.parseConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
case *ssa.Extract: case *ssa.Extract:
value, err := c.parseExpr(frame, expr.Tuple) value := c.getValue(frame, expr.Tuple)
if err != nil {
return llvm.Value{}, err
}
result := c.builder.CreateExtractValue(value, expr.Index, "") result := c.builder.CreateExtractValue(value, expr.Index, "")
return result, nil return result, nil
case *ssa.Field: case *ssa.Field:
value, err := c.parseExpr(frame, expr.X) value := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
if s := expr.X.Type().Underlying().(*types.Struct); s.NumFields() > 2 && s.Field(0).Name() == "C union" { if s := expr.X.Type().Underlying().(*types.Struct); s.NumFields() > 2 && s.Field(0).Name() == "C union" {
// Extract a field from a CGo union. // Extract a field from a CGo union.
// This could be done directly, but as this is a very infrequent // This could be done directly, but as this is a very infrequent
@ -1385,10 +1311,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
result := c.builder.CreateExtractValue(value, expr.Field, "") result := c.builder.CreateExtractValue(value, expr.Field, "")
return result, nil return result, nil
case *ssa.FieldAddr: case *ssa.FieldAddr:
val, err := c.parseExpr(frame, expr.X) val := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
// Check for nil pointer before calculating the address, from the spec: // Check for nil pointer before calculating the address, from the spec:
// > For an operand x of type T, the address operation &x generates a // > For an operand x of type T, the address operation &x generates a
// > pointer of type *T to x. [...] If the evaluation of x would cause a // > pointer of type *T to x. [...] If the evaluation of x would cause a
@ -1409,26 +1332,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
return c.builder.CreateGEP(val, indices, ""), nil return c.builder.CreateGEP(val, indices, ""), nil
} }
case *ssa.Function: case *ssa.Function:
fn := c.ir.GetFunction(expr) panic("function is not an expression")
if fn.IsExported() {
return llvm.Value{}, c.makeError(expr.Pos(), "cannot use an exported function as value")
}
return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature), nil
case *ssa.Global: case *ssa.Global:
value := c.ir.GetGlobal(expr).LLVMGlobal panic("global is not an expression")
if value.IsNil() {
return llvm.Value{}, c.makeError(expr.Pos(), "global not found: "+c.ir.GetGlobal(expr).LinkName())
}
return value, nil
case *ssa.Index: case *ssa.Index:
array, err := c.parseExpr(frame, expr.X) array := c.getValue(frame, expr.X)
if err != nil { index := c.getValue(frame, expr.Index)
return llvm.Value{}, err
}
index, err := c.parseExpr(frame, expr.Index)
if err != nil {
return llvm.Value{}, err
}
// Check bounds. // Check bounds.
arrayLen := expr.X.Type().(*types.Array).Len() arrayLen := expr.X.Type().(*types.Array).Len()
@ -1443,14 +1352,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
ptr := c.builder.CreateGEP(alloca, []llvm.Value{zero, index}, "index.gep") ptr := c.builder.CreateGEP(alloca, []llvm.Value{zero, index}, "index.gep")
return c.builder.CreateLoad(ptr, "index.load"), nil return c.builder.CreateLoad(ptr, "index.load"), nil
case *ssa.IndexAddr: case *ssa.IndexAddr:
val, err := c.parseExpr(frame, expr.X) val := c.getValue(frame, expr.X)
if err != nil { index := c.getValue(frame, expr.Index)
return llvm.Value{}, err
}
index, err := c.parseExpr(frame, expr.Index)
if err != nil {
return llvm.Value{}, err
}
// Get buffer pointer and length // Get buffer pointer and length
var bufptr, buflen llvm.Value var bufptr, buflen llvm.Value
@ -1494,14 +1397,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
panic("unreachable") panic("unreachable")
} }
case *ssa.Lookup: case *ssa.Lookup:
value, err := c.parseExpr(frame, expr.X) value := c.getValue(frame, expr.X)
if err != nil { index := c.getValue(frame, expr.Index)
return llvm.Value{}, nil
}
index, err := c.parseExpr(frame, expr.Index)
if err != nil {
return llvm.Value{}, nil
}
switch xType := expr.X.Type().Underlying().(type) { switch xType := expr.X.Type().Underlying().(type) {
case *types.Basic: case *types.Basic:
// Value type must be a string, which is a basic type. // Value type must be a string, which is a basic type.
@ -1531,10 +1428,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
case *ssa.MakeClosure: case *ssa.MakeClosure:
return c.parseMakeClosure(frame, expr) return c.parseMakeClosure(frame, expr)
case *ssa.MakeInterface: case *ssa.MakeInterface:
val, err := c.parseExpr(frame, expr.X) val := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
return c.parseMakeInterface(val, expr.X.Type(), expr.Pos()) return c.parseMakeInterface(val, expr.X.Type(), expr.Pos())
case *ssa.MakeMap: case *ssa.MakeMap:
mapType := expr.Type().Underlying().(*types.Map) mapType := expr.Type().Underlying().(*types.Map)
@ -1547,14 +1441,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
hashmap := c.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize}, "") hashmap := c.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize}, "")
return hashmap, nil return hashmap, nil
case *ssa.MakeSlice: case *ssa.MakeSlice:
sliceLen, err := c.parseExpr(frame, expr.Len) sliceLen := c.getValue(frame, expr.Len)
if err != nil { sliceCap := c.getValue(frame, expr.Cap)
return llvm.Value{}, nil
}
sliceCap, err := c.parseExpr(frame, expr.Cap)
if err != nil {
return llvm.Value{}, nil
}
sliceType := expr.Type().Underlying().(*types.Slice) sliceType := expr.Type().Underlying().(*types.Slice)
llvmElemType := c.getLLVMType(sliceType.Elem()) llvmElemType := c.getLLVMType(sliceType.Elem())
elemSize := c.targetData.TypeAllocSize(llvmElemType) elemSize := c.targetData.TypeAllocSize(llvmElemType)
@ -1605,14 +1493,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
return slice, nil return slice, nil
case *ssa.Next: case *ssa.Next:
rangeVal := expr.Iter.(*ssa.Range).X rangeVal := expr.Iter.(*ssa.Range).X
llvmRangeVal, err := c.parseExpr(frame, rangeVal) llvmRangeVal := c.getValue(frame, rangeVal)
if err != nil { it := c.getValue(frame, expr.Iter)
return llvm.Value{}, err
}
it, err := c.parseExpr(frame, expr.Iter)
if err != nil {
return llvm.Value{}, err
}
if expr.IsString { if expr.IsString {
return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
} else { // map } else { // map
@ -1672,20 +1554,14 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
if expr.Max != nil { if expr.Max != nil {
return llvm.Value{}, c.makeError(expr.Pos(), "todo: full slice expressions (with max): "+expr.Type().String()) return llvm.Value{}, c.makeError(expr.Pos(), "todo: full slice expressions (with max): "+expr.Type().String())
} }
value, err := c.parseExpr(frame, expr.X) value := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
var lowType, highType *types.Basic var lowType, highType *types.Basic
var low, high llvm.Value var low, high llvm.Value
if expr.Low != nil { if expr.Low != nil {
lowType = expr.Low.Type().Underlying().(*types.Basic) lowType = expr.Low.Type().Underlying().(*types.Basic)
low, err = c.parseExpr(frame, expr.Low) low = c.getValue(frame, expr.Low)
if err != nil {
return llvm.Value{}, nil
}
if low.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if low.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
if lowType.Info()&types.IsUnsigned != 0 { if lowType.Info()&types.IsUnsigned != 0 {
low = c.builder.CreateZExt(low, c.uintptrType, "") low = c.builder.CreateZExt(low, c.uintptrType, "")
@ -1700,10 +1576,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
if expr.High != nil { if expr.High != nil {
highType = expr.High.Type().Underlying().(*types.Basic) highType = expr.High.Type().Underlying().(*types.Basic)
high, err = c.parseExpr(frame, expr.High) high = c.getValue(frame, expr.High)
if err != nil {
return llvm.Value{}, nil
}
if high.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if high.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
if highType.Info()&types.IsUnsigned != 0 { if highType.Info()&types.IsUnsigned != 0 {
high = c.builder.CreateZExt(high, c.uintptrType, "") high = c.builder.CreateZExt(high, c.uintptrType, "")
@ -1819,7 +1692,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
return llvm.Value{}, c.makeError(expr.Pos(), "unknown slice type: "+typ.String()) return llvm.Value{}, c.makeError(expr.Pos(), "unknown slice type: "+typ.String())
} }
case *ssa.TypeAssert: case *ssa.TypeAssert:
return c.parseTypeAssert(frame, expr) return c.parseTypeAssert(frame, expr), nil
case *ssa.UnOp: case *ssa.UnOp:
return c.parseUnOp(frame, expr) return c.parseUnOp(frame, expr)
default: default:
@ -2118,7 +1991,7 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value, p
} }
} }
func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error) { func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value {
switch typ := expr.Type().Underlying().(type) { switch typ := expr.Type().Underlying().(type) {
case *types.Basic: case *types.Basic:
llvmType := c.getLLVMType(typ) llvmType := c.getLLVMType(typ)
@ -2128,7 +2001,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
if b { if b {
n = 1 n = 1
} }
return llvm.ConstInt(llvmType, n, false), nil return llvm.ConstInt(llvmType, n, false)
} else if typ.Info()&types.IsString != 0 { } else if typ.Info()&types.IsString != 0 {
str := constant.StringVal(expr.Value) str := constant.StringVal(expr.Value)
strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false) strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false)
@ -2141,77 +2014,67 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
strPtr := c.builder.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "") strPtr := c.builder.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "")
strObj := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._string"), []llvm.Value{strPtr, strLen}) strObj := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._string"), []llvm.Value{strPtr, strLen})
return strObj, nil return strObj
} else if typ.Kind() == types.UnsafePointer { } else if typ.Kind() == types.UnsafePointer {
if !expr.IsNil() { if !expr.IsNil() {
value, _ := constant.Uint64Val(expr.Value) value, _ := constant.Uint64Val(expr.Value)
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.i8ptrType), nil return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.i8ptrType)
} }
return llvm.ConstNull(c.i8ptrType), nil return llvm.ConstNull(c.i8ptrType)
} else if typ.Info()&types.IsUnsigned != 0 { } else if typ.Info()&types.IsUnsigned != 0 {
n, _ := constant.Uint64Val(expr.Value) n, _ := constant.Uint64Val(expr.Value)
return llvm.ConstInt(llvmType, n, false), nil return llvm.ConstInt(llvmType, n, false)
} else if typ.Info()&types.IsInteger != 0 { // signed } else if typ.Info()&types.IsInteger != 0 { // signed
n, _ := constant.Int64Val(expr.Value) n, _ := constant.Int64Val(expr.Value)
return llvm.ConstInt(llvmType, uint64(n), true), nil return llvm.ConstInt(llvmType, uint64(n), true)
} else if typ.Info()&types.IsFloat != 0 { } else if typ.Info()&types.IsFloat != 0 {
n, _ := constant.Float64Val(expr.Value) n, _ := constant.Float64Val(expr.Value)
return llvm.ConstFloat(llvmType, n), nil return llvm.ConstFloat(llvmType, n)
} else if typ.Kind() == types.Complex64 { } else if typ.Kind() == types.Complex64 {
r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32])) r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
if err != nil { i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
return llvm.Value{}, err
}
i, err := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
if err != nil {
return llvm.Value{}, err
}
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)) cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "") cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil return cplx
} else if typ.Kind() == types.Complex128 { } else if typ.Kind() == types.Complex128 {
r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64])) r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
if err != nil { i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
return llvm.Value{}, err
}
i, err := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
if err != nil {
return llvm.Value{}, err
}
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)) cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "") cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil return cplx
} else { } else {
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String()) panic("unknown constant of basic type: " + expr.String())
} }
case *types.Chan: case *types.Chan:
return c.getZeroValue(c.getLLVMType(expr.Type())), nil if expr.Value != nil {
panic("expected nil chan constant")
}
return c.getZeroValue(c.getLLVMType(expr.Type()))
case *types.Signature: case *types.Signature:
if expr.Value != nil { if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil signature constant") panic("expected nil signature constant")
} }
return c.getZeroValue(c.getLLVMType(expr.Type())), nil return c.getZeroValue(c.getLLVMType(expr.Type()))
case *types.Interface: case *types.Interface:
if expr.Value != nil { if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil interface constant") panic("expected nil interface constant")
} }
// Create a generic nil interface with no dynamic type (typecode=0). // Create a generic nil interface with no dynamic type (typecode=0).
fields := []llvm.Value{ fields := []llvm.Value{
llvm.ConstInt(c.uintptrType, 0, false), llvm.ConstInt(c.uintptrType, 0, false),
llvm.ConstPointerNull(c.i8ptrType), llvm.ConstPointerNull(c.i8ptrType),
} }
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields) return llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)
return itf, nil
case *types.Pointer: case *types.Pointer:
if expr.Value != nil { if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil pointer constant") panic("expected nil pointer constant")
} }
return llvm.ConstPointerNull(c.getLLVMType(typ)), nil return llvm.ConstPointerNull(c.getLLVMType(typ))
case *types.Slice: case *types.Slice:
if expr.Value != nil { if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil slice constant") panic("expected nil slice constant")
} }
elemType := c.getLLVMType(typ.Elem()) elemType := c.getLLVMType(typ.Elem())
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0)) llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
@ -2221,16 +2084,16 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
llvmLen, // len llvmLen, // len
llvmLen, // cap llvmLen, // cap
}, false) }, false)
return slice, nil return slice
case *types.Map: case *types.Map:
if !expr.IsNil() { if !expr.IsNil() {
// I believe this is not allowed by the Go spec. // I believe this is not allowed by the Go spec.
panic("non-nil map constant") panic("non-nil map constant")
} }
llvmType := c.getLLVMType(typ) llvmType := c.getLLVMType(typ)
return c.getZeroValue(llvmType), nil return c.getZeroValue(llvmType)
default: default:
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String()) panic("unknown constant: " + expr.String())
} }
} }
@ -2392,10 +2255,7 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
} }
func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
x, err := c.parseExpr(frame, unop.X) x := c.getValue(frame, unop.X)
if err != nil {
return llvm.Value{}, err
}
switch unop.Op { switch unop.Op {
case token.NOT: // !x case token.NOT: // !x
return c.builder.CreateNot(x, ""), nil return c.builder.CreateNot(x, ""), nil
@ -2441,7 +2301,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
case token.XOR: // ^x, toggle all bits in integer case token.XOR: // ^x, toggle all bits in integer
return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil
case token.ARROW: // <-x, receive from channel case token.ARROW: // <-x, receive from channel
return c.emitChanRecv(frame, unop) return c.emitChanRecv(frame, unop), nil
default: default:
return llvm.Value{}, c.makeError(unop.Pos(), "todo: unknown unop") return llvm.Value{}, c.makeError(unop.Pos(), "todo: unknown unop")
} }

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

@ -56,18 +56,12 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
// 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, err := c.parseExpr(frame, instr.Call.Value) // interface itf := c.getValue(frame, instr.Call.Value) // interface
if err != nil {
return err
}
receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver") receiverValue := c.builder.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, c.i8ptrType)
for _, arg := range instr.Call.Args { for _, arg := range instr.Call.Args {
val, err := c.parseExpr(frame, arg) val := c.getValue(frame, arg)
if err != nil {
return err
}
values = append(values, val) values = append(values, val)
valueTypes = append(valueTypes, val.Type()) valueTypes = append(valueTypes, val.Type())
} }
@ -86,10 +80,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
// 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, err := c.parseExpr(frame, param) llvmParam := c.getValue(frame, param)
if err != nil {
return err
}
values = append(values, llvmParam) values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type()) valueTypes = append(valueTypes, llvmParam.Type())
} }
@ -101,10 +92,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
// 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, err := c.parseExpr(frame, instr.Call.Value) closure := c.getValue(frame, instr.Call.Value)
if err != nil {
return err
}
context := c.builder.CreateExtractValue(closure, 0, "") context := c.builder.CreateExtractValue(closure, 0, "")
// Get the callback number. // Get the callback number.
@ -120,10 +108,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
// 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, err := c.parseExpr(frame, param) llvmParam := c.getValue(frame, param)
if err != nil {
return err
}
values = append(values, llvmParam) values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type()) valueTypes = append(valueTypes, llvmParam.Type())
} }
@ -239,10 +224,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
// Parent coroutine handle. // Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
fnPtr, _, err := c.getInvokeCall(frame, callback) fnPtr, _ := c.getInvokeCall(frame, callback)
if err != nil {
return err
}
c.createCall(fnPtr, forwardParams, "") c.createCall(fnPtr, forwardParams, "")
case *ir.Function: case *ir.Function:

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

@ -190,10 +190,7 @@ func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.V
boundVarTypes := make([]llvm.Type, 0, len(expr.Bindings)) boundVarTypes := make([]llvm.Type, 0, len(expr.Bindings))
for _, binding := range expr.Bindings { for _, binding := range expr.Bindings {
// The context stores the bound variables. // The context stores the bound variables.
llvmBoundVar, err := c.parseExpr(frame, binding) llvmBoundVar := c.getValue(frame, binding)
if err != nil {
return llvm.Value{}, err
}
boundVars = append(boundVars, llvmBoundVar) boundVars = append(boundVars, llvmBoundVar)
boundVarTypes = append(boundVarTypes, llvmBoundVar.Type()) boundVarTypes = append(boundVarTypes, llvmBoundVar.Type())
} }

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

@ -68,11 +68,7 @@ func (c *Compiler) emitAsmFull(frame *Frame, instr *ssa.CallCommon) (llvm.Value,
} }
key := constant.StringVal(r.Key.(*ssa.Const).Value) key := constant.StringVal(r.Key.(*ssa.Const).Value)
//println("value:", r.Value.(*ssa.MakeInterface).X.String()) //println("value:", r.Value.(*ssa.MakeInterface).X.String())
value, err := c.parseExpr(frame, r.Value.(*ssa.MakeInterface).X) registers[key] = c.getValue(frame, r.Value.(*ssa.MakeInterface).X)
if err != nil {
return llvm.Value{}, err
}
registers[key] = value
case *ssa.Call: case *ssa.Call:
if r.Common() == instr { if r.Common() == instr {
break break
@ -145,10 +141,7 @@ func (c *Compiler) emitSVCall(frame *Frame, args []ssa.Value) (llvm.Value, error
} else { } else {
constraints += ",{r" + strconv.Itoa(i) + "}" constraints += ",{r" + strconv.Itoa(i) + "}"
} }
llvmValue, err := c.parseExpr(frame, arg) llvmValue := c.getValue(frame, arg)
if err != nil {
return llvm.Value{}, err
}
llvmArgs = append(llvmArgs, llvmValue) llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type()) argTypes = append(argTypes, llvmValue.Type())
} }

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

@ -274,11 +274,8 @@ func (c *Compiler) getMethodSignature(method *types.Func) llvm.Value {
// //
// Type asserts on concrete types are trivial: just compare type numbers. Type // Type asserts on concrete types are trivial: just compare type numbers. Type
// asserts on interfaces are more difficult, see the comments in the function. // asserts on interfaces are more difficult, see the comments in the function.
func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Value, error) { func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) llvm.Value {
itf, err := c.parseExpr(frame, expr.X) itf := c.getValue(frame, expr.X)
if err != nil {
return llvm.Value{}, err
}
assertedType := c.getLLVMType(expr.AssertedType) assertedType := c.getLLVMType(expr.AssertedType)
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type") actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
@ -368,23 +365,20 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val
tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple
tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
return tuple, nil return tuple
} else { } else {
// This is kind of dirty as the branch above becomes mostly useless, // This is kind of dirty as the branch above becomes mostly useless,
// but hopefully this gets optimized away. // but hopefully this gets optimized away.
c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "") c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "")
return phi, nil return phi
} }
} }
// getInvokeCall creates and returns the function pointer and parameters of an // getInvokeCall creates and returns the function pointer and parameters of an
// interface call. It can be used in a call or defer instruction. // interface call. It can be used in a call or defer instruction.
func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value, error) { func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value) {
// Call an interface method with dynamic dispatch. // Call an interface method with dynamic dispatch.
itf, err := c.parseExpr(frame, instr.Value) // interface itf := c.getValue(frame, instr.Value) // interface
if err != nil {
return llvm.Value{}, nil, err
}
llvmFnType := c.getRawFuncType(instr.Method.Type().(*types.Signature)) llvmFnType := c.getRawFuncType(instr.Method.Type().(*types.Signature))
@ -400,11 +394,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu
args := []llvm.Value{receiverValue} args := []llvm.Value{receiverValue}
for _, arg := range instr.Args { for _, arg := range instr.Args {
val, err := c.parseExpr(frame, arg) args = append(args, c.getValue(frame, arg))
if err != nil {
return llvm.Value{}, nil, err
}
args = append(args, val)
} }
// Add the context parameter. An interface call never takes a context but we // Add the context parameter. An interface call never takes a context but we
// have to supply the parameter anyway. // have to supply the parameter anyway.
@ -412,7 +402,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu
// Add the parent goroutine handle. // Add the parent goroutine handle.
args = append(args, llvm.Undef(c.i8ptrType)) args = append(args, llvm.Undef(c.i8ptrType))
return fnCast, args, nil return fnCast, args
} }
// interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and // interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and

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

@ -51,10 +51,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
"{r12}", "{r12}",
"{r13}", "{r13}",
}[i] }[i]
llvmValue, err := c.parseExpr(frame, arg) llvmValue := c.getValue(frame, arg)
if err != nil {
return llvm.Value{}, err
}
args = append(args, llvmValue) args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type()) argTypes = append(argTypes, llvmValue.Type())
} }
@ -80,10 +77,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
"{r5}", "{r5}",
"{r6}", "{r6}",
}[i] }[i]
llvmValue, err := c.parseExpr(frame, arg) llvmValue := c.getValue(frame, arg)
if err != nil {
return llvm.Value{}, err
}
args = append(args, llvmValue) args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type()) argTypes = append(argTypes, llvmValue.Type())
} }
@ -113,10 +107,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
"{x4}", "{x4}",
"{x5}", "{x5}",
}[i] }[i]
llvmValue, err := c.parseExpr(frame, arg) llvmValue := c.getValue(frame, arg)
if err != nil {
return llvm.Value{}, err
}
args = append(args, llvmValue) args = append(args, llvmValue)
argTypes = append(argTypes, llvmValue.Type()) argTypes = append(argTypes, llvmValue.Type())
} }