compiler: refactor parseExpr
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.
Этот коммит содержится в:
родитель
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
|
||||
// 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())
|
||||
ch, err := c.parseExpr(frame, instr.Chan)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chanValue, err := c.parseExpr(frame, instr.X)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch := c.getValue(frame, instr.Chan)
|
||||
chanValue := c.getValue(frame, instr.X)
|
||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
|
||||
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
|
||||
c.builder.CreateStore(chanValue, valueAlloca)
|
||||
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
|
||||
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
|
||||
// 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())
|
||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
||||
ch, err := c.parseExpr(frame, unop.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
ch := c.getValue(frame, unop.X)
|
||||
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
|
||||
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
|
||||
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 = c.builder.CreateInsertValue(tuple, received, 0, "")
|
||||
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "")
|
||||
return tuple, nil
|
||||
return tuple
|
||||
} else {
|
||||
return received, nil
|
||||
return received
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
||||
ch, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch := c.getValue(frame, param)
|
||||
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 {
|
||||
block := phi.ssa.Block()
|
||||
for i, edge := range phi.ssa.Edges {
|
||||
llvmVal, err := c.parseExpr(frame, edge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmVal := c.getValue(frame, edge)
|
||||
llvmBlock := frame.blockExits[block.Preds[i]]
|
||||
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.
|
||||
var params []llvm.Value
|
||||
for _, param := range instr.Call.Args {
|
||||
val, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params = append(params, val)
|
||||
params = append(params, c.getValue(frame, param))
|
||||
}
|
||||
if !calleeFn.IsExported() {
|
||||
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, "")
|
||||
return nil
|
||||
case *ssa.If:
|
||||
cond, err := c.parseExpr(frame, instr.Cond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cond := c.getValue(frame, instr.Cond)
|
||||
block := instr.Block()
|
||||
blockThen := frame.blockEntries[block.Succs[0]]
|
||||
blockElse := frame.blockEntries[block.Succs[1]]
|
||||
|
@ -894,25 +884,13 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
|
|||
c.builder.CreateBr(blockJump)
|
||||
return nil
|
||||
case *ssa.MapUpdate:
|
||||
m, err := c.parseExpr(frame, instr.Map)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := c.parseExpr(frame, instr.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value, err := c.parseExpr(frame, instr.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := c.getValue(frame, instr.Map)
|
||||
key := c.getValue(frame, instr.Key)
|
||||
value := c.getValue(frame, instr.Value)
|
||||
mapType := instr.Map.Type().Underlying().(*types.Map)
|
||||
return c.emitMapUpdate(mapType.Key(), m, key, value, instr.Pos())
|
||||
case *ssa.Panic:
|
||||
value, err := c.parseExpr(frame, instr.X)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value := c.getValue(frame, instr.X)
|
||||
c.createRuntimeCall("_panic", []llvm.Value{value}, "")
|
||||
c.builder.CreateUnreachable()
|
||||
return nil
|
||||
|
@ -921,20 +899,13 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
|
|||
c.builder.CreateRetVoid()
|
||||
return nil
|
||||
} else if len(instr.Results) == 1 {
|
||||
val, err := c.parseExpr(frame, instr.Results[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.builder.CreateRet(val)
|
||||
c.builder.CreateRet(c.getValue(frame, instr.Results[0]))
|
||||
return nil
|
||||
} else {
|
||||
// Multiple return values. Put them all in a struct.
|
||||
retVal := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType())
|
||||
for i, result := range instr.Results {
|
||||
val, err := c.parseExpr(frame, result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val := c.getValue(frame, result)
|
||||
retVal = c.builder.CreateInsertValue(retVal, val, i, "")
|
||||
}
|
||||
c.builder.CreateRet(retVal)
|
||||
|
@ -943,16 +914,11 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
|
|||
case *ssa.RunDefers:
|
||||
return c.emitRunDefers(frame)
|
||||
case *ssa.Send:
|
||||
return c.emitChanSend(frame, instr)
|
||||
c.emitChanSend(frame, instr)
|
||||
return nil
|
||||
case *ssa.Store:
|
||||
llvmAddr, err := c.parseExpr(frame, instr.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmVal, err := c.parseExpr(frame, instr.Val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmAddr := c.getValue(frame, instr.Addr)
|
||||
llvmVal := c.getValue(frame, instr.Val)
|
||||
if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
|
||||
// nothing to store
|
||||
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) {
|
||||
switch callName {
|
||||
case "append":
|
||||
src, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
elems, err := c.parseExpr(frame, args[1])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
src := c.getValue(frame, args[0])
|
||||
elems := c.getValue(frame, args[1])
|
||||
srcBuf := c.builder.CreateExtractValue(src, 0, "append.srcBuf")
|
||||
srcPtr := c.builder.CreateBitCast(srcBuf, c.i8ptrType, "append.srcPtr")
|
||||
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, "")
|
||||
return newSlice, nil
|
||||
case "cap":
|
||||
value, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, args[0])
|
||||
var llvmCap llvm.Value
|
||||
switch args[0].Type().(type) {
|
||||
case *types.Chan:
|
||||
|
@ -1020,16 +977,11 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string,
|
|||
}
|
||||
return llvmCap, nil
|
||||
case "close":
|
||||
return llvm.Value{}, c.emitChanClose(frame, args[0])
|
||||
c.emitChanClose(frame, args[0])
|
||||
return llvm.Value{}, nil
|
||||
case "complex":
|
||||
r, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
i, err := c.parseExpr(frame, args[1])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
r := c.getValue(frame, args[0])
|
||||
i := c.getValue(frame, args[1])
|
||||
t := args[0].Type().Underlying().(*types.Basic)
|
||||
var cplx llvm.Value
|
||||
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, "")
|
||||
return cplx, nil
|
||||
case "copy":
|
||||
dst, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
src, err := c.parseExpr(frame, args[1])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
dst := c.getValue(frame, args[0])
|
||||
src := c.getValue(frame, args[1])
|
||||
dstLen := c.builder.CreateExtractValue(dst, 1, "copy.dstLen")
|
||||
srcLen := c.builder.CreateExtractValue(src, 1, "copy.srcLen")
|
||||
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)
|
||||
return c.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil
|
||||
case "delete":
|
||||
m, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
key, err := c.parseExpr(frame, args[1])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
m := c.getValue(frame, args[0])
|
||||
key := c.getValue(frame, args[1])
|
||||
return llvm.Value{}, c.emitMapDelete(args[1].Type(), m, key, pos)
|
||||
case "imag":
|
||||
cplx, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
cplx := c.getValue(frame, args[0])
|
||||
return c.builder.CreateExtractValue(cplx, 1, "imag"), nil
|
||||
case "len":
|
||||
value, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, args[0])
|
||||
var llvmLen llvm.Value
|
||||
switch args[0].Type().Underlying().(type) {
|
||||
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" {
|
||||
c.createRuntimeCall("printspace", nil, "")
|
||||
}
|
||||
value, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, arg)
|
||||
typ := arg.Type().Underlying()
|
||||
switch typ := typ.(type) {
|
||||
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
|
||||
case "real":
|
||||
cplx, err := c.parseExpr(frame, args[0])
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
cplx := c.getValue(frame, args[0])
|
||||
return c.builder.CreateExtractValue(cplx, 0, "real"), nil
|
||||
case "recover":
|
||||
return c.createRuntimeCall("_recover", nil, ""), nil
|
||||
case "ssa:wrapnilchk":
|
||||
// TODO: do an actual nil check?
|
||||
return c.parseExpr(frame, args[0])
|
||||
return c.getValue(frame, args[0]), nil
|
||||
default:
|
||||
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
|
||||
for _, param := range args {
|
||||
val, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
params = append(params, val)
|
||||
params = append(params, c.getValue(frame, param))
|
||||
}
|
||||
|
||||
if !exported {
|
||||
|
@ -1195,15 +1119,12 @@ func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, con
|
|||
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) {
|
||||
if instr.IsInvoke() {
|
||||
fnCast, args, err := c.getInvokeCall(frame, instr)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
fnCast, args := c.getInvokeCall(frame, instr)
|
||||
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:
|
||||
// A call on a func value, but the callee is trivial to find. For
|
||||
// example: immediately applied functions.
|
||||
funcValue, err := c.parseExpr(frame, value)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
funcValue := c.getValue(frame, value)
|
||||
context = c.extractFuncContext(funcValue)
|
||||
default:
|
||||
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.
|
||||
|
@ -1250,10 +1168,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
|
|||
case *ssa.Builtin:
|
||||
return c.parseBuiltin(frame, instr.Args, call.Name(), instr.Pos())
|
||||
default: // function pointer
|
||||
value, err := c.parseExpr(frame, instr.Value)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, instr.Value)
|
||||
// This is a func value, which cannot be called directly. We have to
|
||||
// extract the function pointer and context first from the func value.
|
||||
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
|
||||
}
|
||||
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) {
|
||||
if value, ok := frame.locals[expr]; ok {
|
||||
// Value is a local variable that has already been computed.
|
||||
if value.IsNil() {
|
||||
return llvm.Value{}, c.makeError(expr.Pos(), "undefined local var (from cgo?)")
|
||||
// getValue returns the LLVM value of a constant, function value, global, or
|
||||
// already processed SSA expression.
|
||||
func (c *Compiler) getValue(frame *Frame, expr ssa.Value) llvm.Value {
|
||||
switch expr := expr.(type) {
|
||||
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) {
|
||||
|
@ -1298,14 +1242,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
}
|
||||
return buf, nil
|
||||
case *ssa.BinOp:
|
||||
x, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
y, err := c.parseExpr(frame, expr.Y)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
x := c.getValue(frame, expr.X)
|
||||
y := c.getValue(frame, expr.Y)
|
||||
return c.parseBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos())
|
||||
case *ssa.Call:
|
||||
// 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
|
||||
// heap allocation and because it's easier to implement, see:
|
||||
// https://research.swtch.com/interfaces
|
||||
return c.parseExpr(frame, expr.X)
|
||||
return c.getValue(frame, expr.X), nil
|
||||
case *ssa.ChangeType:
|
||||
// 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
|
||||
// LLVM type as well.
|
||||
x, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
x := c.getValue(frame, expr.X)
|
||||
llvmType := c.getLLVMType(expr.Type())
|
||||
if x.Type() == llvmType {
|
||||
// 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())
|
||||
}
|
||||
case *ssa.Const:
|
||||
return c.parseConst(frame.fn.LinkName(), expr)
|
||||
panic("const is not an expression")
|
||||
case *ssa.Convert:
|
||||
x, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
x := c.getValue(frame, expr.X)
|
||||
return c.parseConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
|
||||
case *ssa.Extract:
|
||||
value, err := c.parseExpr(frame, expr.Tuple)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, expr.Tuple)
|
||||
result := c.builder.CreateExtractValue(value, expr.Index, "")
|
||||
return result, nil
|
||||
case *ssa.Field:
|
||||
value, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, expr.X)
|
||||
if s := expr.X.Type().Underlying().(*types.Struct); s.NumFields() > 2 && s.Field(0).Name() == "C union" {
|
||||
// Extract a field from a CGo union.
|
||||
// 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, "")
|
||||
return result, nil
|
||||
case *ssa.FieldAddr:
|
||||
val, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
val := c.getValue(frame, expr.X)
|
||||
// Check for nil pointer before calculating the address, from the spec:
|
||||
// > 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
|
||||
|
@ -1409,26 +1332,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
return c.builder.CreateGEP(val, indices, ""), nil
|
||||
}
|
||||
case *ssa.Function:
|
||||
fn := c.ir.GetFunction(expr)
|
||||
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
|
||||
panic("function is not an expression")
|
||||
case *ssa.Global:
|
||||
value := c.ir.GetGlobal(expr).LLVMGlobal
|
||||
if value.IsNil() {
|
||||
return llvm.Value{}, c.makeError(expr.Pos(), "global not found: "+c.ir.GetGlobal(expr).LinkName())
|
||||
}
|
||||
return value, nil
|
||||
panic("global is not an expression")
|
||||
case *ssa.Index:
|
||||
array, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
index, err := c.parseExpr(frame, expr.Index)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
array := c.getValue(frame, expr.X)
|
||||
index := c.getValue(frame, expr.Index)
|
||||
|
||||
// Check bounds.
|
||||
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")
|
||||
return c.builder.CreateLoad(ptr, "index.load"), nil
|
||||
case *ssa.IndexAddr:
|
||||
val, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
index, err := c.parseExpr(frame, expr.Index)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
val := c.getValue(frame, expr.X)
|
||||
index := c.getValue(frame, expr.Index)
|
||||
|
||||
// Get buffer pointer and length
|
||||
var bufptr, buflen llvm.Value
|
||||
|
@ -1494,14 +1397,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
panic("unreachable")
|
||||
}
|
||||
case *ssa.Lookup:
|
||||
value, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
index, err := c.parseExpr(frame, expr.Index)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
value := c.getValue(frame, expr.X)
|
||||
index := c.getValue(frame, expr.Index)
|
||||
switch xType := expr.X.Type().Underlying().(type) {
|
||||
case *types.Basic:
|
||||
// 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:
|
||||
return c.parseMakeClosure(frame, expr)
|
||||
case *ssa.MakeInterface:
|
||||
val, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
val := c.getValue(frame, expr.X)
|
||||
return c.parseMakeInterface(val, expr.X.Type(), expr.Pos())
|
||||
case *ssa.MakeMap:
|
||||
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}, "")
|
||||
return hashmap, nil
|
||||
case *ssa.MakeSlice:
|
||||
sliceLen, err := c.parseExpr(frame, expr.Len)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
sliceCap, err := c.parseExpr(frame, expr.Cap)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
sliceLen := c.getValue(frame, expr.Len)
|
||||
sliceCap := c.getValue(frame, expr.Cap)
|
||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||
llvmElemType := c.getLLVMType(sliceType.Elem())
|
||||
elemSize := c.targetData.TypeAllocSize(llvmElemType)
|
||||
|
@ -1605,14 +1493,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
return slice, nil
|
||||
case *ssa.Next:
|
||||
rangeVal := expr.Iter.(*ssa.Range).X
|
||||
llvmRangeVal, err := c.parseExpr(frame, rangeVal)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
it, err := c.parseExpr(frame, expr.Iter)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmRangeVal := c.getValue(frame, rangeVal)
|
||||
it := c.getValue(frame, expr.Iter)
|
||||
if expr.IsString {
|
||||
return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
||||
} else { // map
|
||||
|
@ -1672,20 +1554,14 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if expr.Max != nil {
|
||||
return llvm.Value{}, c.makeError(expr.Pos(), "todo: full slice expressions (with max): "+expr.Type().String())
|
||||
}
|
||||
value, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
value := c.getValue(frame, expr.X)
|
||||
|
||||
var lowType, highType *types.Basic
|
||||
var low, high llvm.Value
|
||||
|
||||
if expr.Low != nil {
|
||||
lowType = expr.Low.Type().Underlying().(*types.Basic)
|
||||
low, err = c.parseExpr(frame, expr.Low)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
low = c.getValue(frame, expr.Low)
|
||||
if low.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
|
||||
if lowType.Info()&types.IsUnsigned != 0 {
|
||||
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 {
|
||||
highType = expr.High.Type().Underlying().(*types.Basic)
|
||||
high, err = c.parseExpr(frame, expr.High)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
high = c.getValue(frame, expr.High)
|
||||
if high.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
|
||||
if highType.Info()&types.IsUnsigned != 0 {
|
||||
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())
|
||||
}
|
||||
case *ssa.TypeAssert:
|
||||
return c.parseTypeAssert(frame, expr)
|
||||
return c.parseTypeAssert(frame, expr), nil
|
||||
case *ssa.UnOp:
|
||||
return c.parseUnOp(frame, expr)
|
||||
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) {
|
||||
case *types.Basic:
|
||||
llvmType := c.getLLVMType(typ)
|
||||
|
@ -2128,7 +2001,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
if b {
|
||||
n = 1
|
||||
}
|
||||
return llvm.ConstInt(llvmType, n, false), nil
|
||||
return llvm.ConstInt(llvmType, n, false)
|
||||
} else if typ.Info()&types.IsString != 0 {
|
||||
str := constant.StringVal(expr.Value)
|
||||
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)
|
||||
strPtr := c.builder.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "")
|
||||
strObj := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._string"), []llvm.Value{strPtr, strLen})
|
||||
return strObj, nil
|
||||
return strObj
|
||||
} else if typ.Kind() == types.UnsafePointer {
|
||||
if !expr.IsNil() {
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
n, _ := constant.Float64Val(expr.Value)
|
||||
return llvm.ConstFloat(llvmType, n), nil
|
||||
return llvm.ConstFloat(llvmType, n)
|
||||
} else if typ.Kind() == types.Complex64 {
|
||||
r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]))
|
||||
i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]))
|
||||
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, i, 1, "")
|
||||
return cplx, nil
|
||||
return cplx
|
||||
} else if typ.Kind() == types.Complex128 {
|
||||
r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
|
||||
i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
|
||||
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, i, 1, "")
|
||||
return cplx, nil
|
||||
return cplx
|
||||
} else {
|
||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||
panic("unknown constant of basic type: " + expr.String())
|
||||
}
|
||||
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:
|
||||
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:
|
||||
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).
|
||||
fields := []llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, 0, false),
|
||||
llvm.ConstPointerNull(c.i8ptrType),
|
||||
}
|
||||
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)
|
||||
return itf, nil
|
||||
return llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)
|
||||
case *types.Pointer:
|
||||
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:
|
||||
if expr.Value != nil {
|
||||
return llvm.Value{}, errors.New("non-nil slice constant")
|
||||
panic("expected nil slice constant")
|
||||
}
|
||||
elemType := c.getLLVMType(typ.Elem())
|
||||
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, // cap
|
||||
}, false)
|
||||
return slice, nil
|
||||
return slice
|
||||
case *types.Map:
|
||||
if !expr.IsNil() {
|
||||
// I believe this is not allowed by the Go spec.
|
||||
panic("non-nil map constant")
|
||||
}
|
||||
llvmType := c.getLLVMType(typ)
|
||||
return c.getZeroValue(llvmType), nil
|
||||
return c.getZeroValue(llvmType)
|
||||
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) {
|
||||
x, err := c.parseExpr(frame, unop.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
x := c.getValue(frame, unop.X)
|
||||
switch unop.Op {
|
||||
case token.NOT: // !x
|
||||
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
|
||||
return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil
|
||||
case token.ARROW: // <-x, receive from channel
|
||||
return c.emitChanRecv(frame, unop)
|
||||
return c.emitChanRecv(frame, unop), nil
|
||||
default:
|
||||
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
|
||||
// runtime._defer fields, followed by the call parameters).
|
||||
itf, err := c.parseExpr(frame, instr.Call.Value) // interface
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
itf := c.getValue(frame, instr.Call.Value) // interface
|
||||
receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver")
|
||||
values = []llvm.Value{callback, next, receiverValue}
|
||||
valueTypes = append(valueTypes, c.i8ptrType)
|
||||
for _, arg := range instr.Call.Args {
|
||||
val, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val := c.getValue(frame, arg)
|
||||
values = append(values, val)
|
||||
valueTypes = append(valueTypes, val.Type())
|
||||
}
|
||||
|
@ -86,10 +80,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
|
|||
// runtime._defer fields).
|
||||
values = []llvm.Value{callback, next}
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmParam := c.getValue(frame, param)
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
|
@ -101,10 +92,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
|
|||
// pointer.
|
||||
// TODO: ignore this closure entirely and put pointers to the free
|
||||
// variables directly in the defer struct, avoiding a memory allocation.
|
||||
closure, err := c.parseExpr(frame, instr.Call.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
closure := c.getValue(frame, instr.Call.Value)
|
||||
context := c.builder.CreateExtractValue(closure, 0, "")
|
||||
|
||||
// Get the callback number.
|
||||
|
@ -120,10 +108,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error {
|
|||
// context pointer).
|
||||
values = []llvm.Value{callback, next}
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmParam := c.getValue(frame, param)
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
|
@ -239,10 +224,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
|||
// Parent coroutine handle.
|
||||
forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType))
|
||||
|
||||
fnPtr, _, err := c.getInvokeCall(frame, callback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fnPtr, _ := c.getInvokeCall(frame, callback)
|
||||
c.createCall(fnPtr, forwardParams, "")
|
||||
|
||||
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))
|
||||
for _, binding := range expr.Bindings {
|
||||
// The context stores the bound variables.
|
||||
llvmBoundVar, err := c.parseExpr(frame, binding)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmBoundVar := c.getValue(frame, binding)
|
||||
boundVars = append(boundVars, llvmBoundVar)
|
||||
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)
|
||||
//println("value:", r.Value.(*ssa.MakeInterface).X.String())
|
||||
value, err := c.parseExpr(frame, r.Value.(*ssa.MakeInterface).X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
registers[key] = value
|
||||
registers[key] = c.getValue(frame, r.Value.(*ssa.MakeInterface).X)
|
||||
case *ssa.Call:
|
||||
if r.Common() == instr {
|
||||
break
|
||||
|
@ -145,10 +141,7 @@ func (c *Compiler) emitSVCall(frame *Frame, args []ssa.Value) (llvm.Value, error
|
|||
} else {
|
||||
constraints += ",{r" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
llvmValue, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValue := c.getValue(frame, arg)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
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
|
||||
// asserts on interfaces are more difficult, see the comments in the function.
|
||||
func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Value, error) {
|
||||
itf, err := c.parseExpr(frame, expr.X)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) llvm.Value {
|
||||
itf := c.getValue(frame, expr.X)
|
||||
assertedType := c.getLLVMType(expr.AssertedType)
|
||||
|
||||
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.builder.CreateInsertValue(tuple, phi, 0, "") // insert value
|
||||
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
|
||||
return tuple, nil
|
||||
return tuple
|
||||
} else {
|
||||
// This is kind of dirty as the branch above becomes mostly useless,
|
||||
// but hopefully this gets optimized away.
|
||||
c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "")
|
||||
return phi, nil
|
||||
return phi
|
||||
}
|
||||
}
|
||||
|
||||
// getInvokeCall creates and returns the function pointer and parameters of an
|
||||
// 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.
|
||||
itf, err := c.parseExpr(frame, instr.Value) // interface
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil, err
|
||||
}
|
||||
itf := c.getValue(frame, instr.Value) // interface
|
||||
|
||||
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}
|
||||
for _, arg := range instr.Args {
|
||||
val, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil, err
|
||||
}
|
||||
args = append(args, val)
|
||||
args = append(args, c.getValue(frame, arg))
|
||||
}
|
||||
// Add the context parameter. An interface call never takes a context but we
|
||||
// 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.
|
||||
args = append(args, llvm.Undef(c.i8ptrType))
|
||||
|
||||
return fnCast, args, nil
|
||||
return fnCast, args
|
||||
}
|
||||
|
||||
// interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and
|
||||
|
|
|
@ -51,10 +51,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
|||
"{r12}",
|
||||
"{r13}",
|
||||
}[i]
|
||||
llvmValue, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValue := c.getValue(frame, arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
|
@ -80,10 +77,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
|||
"{r5}",
|
||||
"{r6}",
|
||||
}[i]
|
||||
llvmValue, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValue := c.getValue(frame, arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
|
@ -113,10 +107,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
|||
"{x4}",
|
||||
"{x5}",
|
||||
}[i]
|
||||
llvmValue, err := c.parseExpr(frame, arg)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValue := c.getValue(frame, arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче