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
|
// 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())
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче