compiler: do not return an error from getLLVMType
This commit replaces "unknown type" errors in getLLVMType with panics. The main reason this is done is that it simplifies the code *a lot*. Many `if err != nil` lines were there just because of type information. Additionally, simply panicking is probably a better approach as the only way this error can be produced is either with big new language features or a serious compiler bug. Panicking is probably a better way to handle this error anyway.
Этот коммит содержится в:
родитель
6d23809218
коммит
c25fe609a9
6 изменённых файлов: 101 добавлений и 293 удалений
|
@ -12,10 +12,7 @@ import (
|
||||||
|
|
||||||
// emitMakeChan returns a new channel value for the given channel type.
|
// emitMakeChan returns a new channel value for the given channel type.
|
||||||
func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
|
func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
|
||||||
valueType, err := c.getLLVMType(expr.Type().(*types.Chan).Elem())
|
valueType := c.getLLVMType(expr.Type().(*types.Chan).Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
if c.targetData.TypeAllocSize(valueType) > c.targetData.TypeAllocSize(c.intType) {
|
if c.targetData.TypeAllocSize(valueType) > c.targetData.TypeAllocSize(c.intType) {
|
||||||
// Values bigger than int overflow the data part of the coroutine.
|
// Values bigger than int overflow the data part of the coroutine.
|
||||||
// TODO: make the coroutine data part big enough to hold these bigger
|
// TODO: make the coroutine data part big enough to hold these bigger
|
||||||
|
@ -33,10 +30,7 @@ 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) error {
|
||||||
valueType, err := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
|
valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ch, err := c.parseExpr(frame, instr.Chan)
|
ch, err := c.parseExpr(frame, instr.Chan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -56,10 +50,7 @@ func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error {
|
||||||
// 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, error) {
|
||||||
valueType, err := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
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, err := c.parseExpr(frame, unop.X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -83,11 +74,8 @@ func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error
|
||||||
|
|
||||||
// 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) error {
|
||||||
valueType, err := 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)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ch, err := c.parseExpr(frame, param)
|
ch, err := c.parseExpr(frame, param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -274,10 +274,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
for _, t := range c.ir.NamedTypes {
|
for _, t := range c.ir.NamedTypes {
|
||||||
if named, ok := t.Type.Type().(*types.Named); ok {
|
if named, ok := t.Type.Type().(*types.Named); ok {
|
||||||
if st, ok := named.Underlying().(*types.Struct); ok {
|
if st, ok := named.Underlying().(*types.Struct); ok {
|
||||||
llvmType, err := c.getLLVMType(st)
|
llvmType := c.getLLVMType(st)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.LLVMType.StructSetBody(llvmType.StructElementTypes(), false)
|
t.LLVMType.StructSetBody(llvmType.StructElementTypes(), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,10 +283,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
// Declare all globals.
|
// Declare all globals.
|
||||||
for _, g := range c.ir.Globals {
|
for _, g := range c.ir.Globals {
|
||||||
typ := g.Type().(*types.Pointer).Elem()
|
typ := g.Type().(*types.Pointer).Elem()
|
||||||
llvmType, err := c.getLLVMType(typ)
|
llvmType := c.getLLVMType(typ)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
global := c.mod.NamedGlobal(g.LinkName())
|
global := c.mod.NamedGlobal(g.LinkName())
|
||||||
if global.IsNil() {
|
if global.IsNil() {
|
||||||
global = llvm.AddGlobal(c.mod, llvmType, g.LinkName())
|
global = llvm.AddGlobal(c.mod, llvmType, g.LinkName())
|
||||||
|
@ -303,11 +297,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
|
|
||||||
// Declare all functions.
|
// Declare all functions.
|
||||||
for _, f := range c.ir.Functions {
|
for _, f := range c.ir.Functions {
|
||||||
frame, err := c.parseFuncDecl(f)
|
frames = append(frames, c.parseFuncDecl(f))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
frames = append(frames, frame)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add definitions to declarations.
|
// Add definitions to declarations.
|
||||||
|
@ -330,10 +320,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
// Define the already declared functions that wrap methods for use in
|
// Define the already declared functions that wrap methods for use in
|
||||||
// interfaces.
|
// interfaces.
|
||||||
for _, state := range c.interfaceInvokeWrappers {
|
for _, state := range c.interfaceInvokeWrappers {
|
||||||
err = c.createInterfaceInvokeWrapper(state)
|
c.createInterfaceInvokeWrapper(state)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// After all packages are imported, add a synthetic initializer function
|
// After all packages are imported, add a synthetic initializer function
|
||||||
|
@ -342,10 +329,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
initFn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
initFn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
||||||
initFn.LLVMFn.SetUnnamedAddr(true)
|
initFn.LLVMFn.SetUnnamedAddr(true)
|
||||||
if c.Debug {
|
if c.Debug {
|
||||||
difunc, err := c.attachDebugInfo(initFn)
|
difunc := c.attachDebugInfo(initFn)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pos := c.ir.Program.Fset.Position(initFn.Pos())
|
pos := c.ir.Program.Fset.Position(initFn.Pos())
|
||||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
|
@ -411,87 +395,74 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
func (c *Compiler) getLLVMType(goType types.Type) llvm.Type {
|
||||||
switch typ := goType.(type) {
|
switch typ := goType.(type) {
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
elemType, err := c.getLLVMType(typ.Elem())
|
elemType := c.getLLVMType(typ.Elem())
|
||||||
if err != nil {
|
return llvm.ArrayType(elemType, int(typ.Len()))
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
return llvm.ArrayType(elemType, int(typ.Len())), nil
|
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case types.Bool, types.UntypedBool:
|
case types.Bool, types.UntypedBool:
|
||||||
return c.ctx.Int1Type(), nil
|
return c.ctx.Int1Type()
|
||||||
case types.Int8, types.Uint8:
|
case types.Int8, types.Uint8:
|
||||||
return c.ctx.Int8Type(), nil
|
return c.ctx.Int8Type()
|
||||||
case types.Int16, types.Uint16:
|
case types.Int16, types.Uint16:
|
||||||
return c.ctx.Int16Type(), nil
|
return c.ctx.Int16Type()
|
||||||
case types.Int32, types.Uint32:
|
case types.Int32, types.Uint32:
|
||||||
return c.ctx.Int32Type(), nil
|
return c.ctx.Int32Type()
|
||||||
case types.Int, types.Uint:
|
case types.Int, types.Uint:
|
||||||
return c.intType, nil
|
return c.intType
|
||||||
case types.Int64, types.Uint64:
|
case types.Int64, types.Uint64:
|
||||||
return c.ctx.Int64Type(), nil
|
return c.ctx.Int64Type()
|
||||||
case types.Float32:
|
case types.Float32:
|
||||||
return c.ctx.FloatType(), nil
|
return c.ctx.FloatType()
|
||||||
case types.Float64:
|
case types.Float64:
|
||||||
return c.ctx.DoubleType(), nil
|
return c.ctx.DoubleType()
|
||||||
case types.Complex64:
|
case types.Complex64:
|
||||||
return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false), nil
|
return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)
|
||||||
case types.Complex128:
|
case types.Complex128:
|
||||||
return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false), nil
|
return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)
|
||||||
case types.String, types.UntypedString:
|
case types.String, types.UntypedString:
|
||||||
return c.mod.GetTypeByName("runtime._string"), nil
|
return c.mod.GetTypeByName("runtime._string")
|
||||||
case types.Uintptr:
|
case types.Uintptr:
|
||||||
return c.uintptrType, nil
|
return c.uintptrType
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
return c.i8ptrType, nil
|
return c.i8ptrType
|
||||||
default:
|
default:
|
||||||
return llvm.Type{}, errors.New("todo: unknown basic type: " + typ.String())
|
panic("unknown basic type: " + typ.String())
|
||||||
}
|
}
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.channel"), 0), nil
|
return llvm.PointerType(c.mod.GetTypeByName("runtime.channel"), 0)
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
return c.mod.GetTypeByName("runtime._interface"), nil
|
return c.mod.GetTypeByName("runtime._interface")
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.hashmap"), 0), nil
|
return llvm.PointerType(c.mod.GetTypeByName("runtime.hashmap"), 0)
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
if _, ok := typ.Underlying().(*types.Struct); ok {
|
if _, ok := typ.Underlying().(*types.Struct); ok {
|
||||||
llvmType := c.mod.GetTypeByName(typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
llvmType := c.mod.GetTypeByName(typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
||||||
if llvmType.IsNil() {
|
if llvmType.IsNil() {
|
||||||
return llvm.Type{}, errors.New("type not found: " + typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
panic("underlying type not found: " + typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
||||||
}
|
}
|
||||||
return llvmType, nil
|
return llvmType
|
||||||
}
|
}
|
||||||
return c.getLLVMType(typ.Underlying())
|
return c.getLLVMType(typ.Underlying())
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
ptrTo, err := c.getLLVMType(typ.Elem())
|
ptrTo := c.getLLVMType(typ.Elem())
|
||||||
if err != nil {
|
return llvm.PointerType(ptrTo, 0)
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
return llvm.PointerType(ptrTo, 0), nil
|
|
||||||
case *types.Signature: // function value
|
case *types.Signature: // function value
|
||||||
return c.getFuncType(typ)
|
return c.getFuncType(typ)
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
elemType, err := c.getLLVMType(typ.Elem())
|
elemType := c.getLLVMType(typ.Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
members := []llvm.Type{
|
members := []llvm.Type{
|
||||||
llvm.PointerType(elemType, 0),
|
llvm.PointerType(elemType, 0),
|
||||||
c.uintptrType, // len
|
c.uintptrType, // len
|
||||||
c.uintptrType, // cap
|
c.uintptrType, // cap
|
||||||
}
|
}
|
||||||
return c.ctx.StructType(members, false), nil
|
return c.ctx.StructType(members, false)
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
members := make([]llvm.Type, typ.NumFields())
|
members := make([]llvm.Type, typ.NumFields())
|
||||||
for i := 0; i < typ.NumFields(); i++ {
|
for i := 0; i < typ.NumFields(); i++ {
|
||||||
member, err := c.getLLVMType(typ.Field(i).Type())
|
members[i] = c.getLLVMType(typ.Field(i).Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
members[i] = member
|
|
||||||
}
|
}
|
||||||
if len(members) > 2 && typ.Field(0).Name() == "C union" {
|
if len(members) > 2 && typ.Field(0).Name() == "C union" {
|
||||||
// Not a normal struct but a C union emitted by cgo.
|
// Not a normal struct but a C union emitted by cgo.
|
||||||
|
@ -520,19 +491,15 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
||||||
members = append(members, llvm.ArrayType(c.ctx.Int8Type(), int(maxSize-mainTypeSize)))
|
members = append(members, llvm.ArrayType(c.ctx.Int8Type(), int(maxSize-mainTypeSize)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.ctx.StructType(members, false), nil
|
return c.ctx.StructType(members, false)
|
||||||
case *types.Tuple:
|
case *types.Tuple:
|
||||||
members := make([]llvm.Type, typ.Len())
|
members := make([]llvm.Type, typ.Len())
|
||||||
for i := 0; i < typ.Len(); i++ {
|
for i := 0; i < typ.Len(); i++ {
|
||||||
member, err := c.getLLVMType(typ.At(i).Type())
|
members[i] = c.getLLVMType(typ.At(i).Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
members[i] = member
|
|
||||||
}
|
}
|
||||||
return c.ctx.StructType(members, false), nil
|
return c.ctx.StructType(members, false)
|
||||||
default:
|
default:
|
||||||
return llvm.Type{}, errors.New("todo: unknown type: " + goType.String())
|
panic("unknown type: " + goType.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,15 +551,12 @@ func isPointer(typ types.Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the DWARF type for this Go type.
|
// Get the DWARF type for this Go type.
|
||||||
func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
|
func (c *Compiler) getDIType(typ types.Type) llvm.Metadata {
|
||||||
name := typ.String()
|
name := typ.String()
|
||||||
if dityp, ok := c.ditypes[name]; ok {
|
if dityp, ok := c.ditypes[name]; ok {
|
||||||
return dityp, nil
|
return dityp
|
||||||
} else {
|
} else {
|
||||||
llvmType, err := c.getLLVMType(typ)
|
llvmType := c.getLLVMType(typ)
|
||||||
if err != nil {
|
|
||||||
return llvm.Metadata{}, err
|
|
||||||
}
|
|
||||||
sizeInBytes := c.targetData.TypeAllocSize(llvmType)
|
sizeInBytes := c.targetData.TypeAllocSize(llvmType)
|
||||||
var encoding llvm.DwarfTypeEncoding
|
var encoding llvm.DwarfTypeEncoding
|
||||||
switch typ := typ.(type) {
|
switch typ := typ.(type) {
|
||||||
|
@ -620,11 +584,11 @@ func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
|
||||||
Encoding: encoding,
|
Encoding: encoding,
|
||||||
})
|
})
|
||||||
c.ditypes[name] = dityp
|
c.ditypes[name] = dityp
|
||||||
return dityp, nil
|
return dityp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
func (c *Compiler) parseFuncDecl(f *ir.Function) *Frame {
|
||||||
frame := &Frame{
|
frame := &Frame{
|
||||||
fn: f,
|
fn: f,
|
||||||
locals: make(map[ssa.Value]llvm.Value),
|
locals: make(map[ssa.Value]llvm.Value),
|
||||||
|
@ -636,29 +600,18 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
||||||
if f.Signature.Results() == nil {
|
if f.Signature.Results() == nil {
|
||||||
retType = c.ctx.VoidType()
|
retType = c.ctx.VoidType()
|
||||||
} else if f.Signature.Results().Len() == 1 {
|
} else if f.Signature.Results().Len() == 1 {
|
||||||
var err error
|
retType = c.getLLVMType(f.Signature.Results().At(0).Type())
|
||||||
retType, err = c.getLLVMType(f.Signature.Results().At(0).Type())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
results := make([]llvm.Type, 0, f.Signature.Results().Len())
|
results := make([]llvm.Type, 0, f.Signature.Results().Len())
|
||||||
for i := 0; i < f.Signature.Results().Len(); i++ {
|
for i := 0; i < f.Signature.Results().Len(); i++ {
|
||||||
typ, err := c.getLLVMType(f.Signature.Results().At(i).Type())
|
results = append(results, c.getLLVMType(f.Signature.Results().At(i).Type()))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
results = append(results, typ)
|
|
||||||
}
|
}
|
||||||
retType = c.ctx.StructType(results, false)
|
retType = c.ctx.StructType(results, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramTypes []llvm.Type
|
var paramTypes []llvm.Type
|
||||||
for _, param := range f.Params {
|
for _, param := range f.Params {
|
||||||
paramType, err := c.getLLVMType(param.Type())
|
paramType := c.getLLVMType(param.Type())
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
paramTypeFragments := c.expandFormalParamType(paramType)
|
paramTypeFragments := c.expandFormalParamType(paramType)
|
||||||
paramTypes = append(paramTypes, paramTypeFragments...)
|
paramTypes = append(paramTypes, paramTypeFragments...)
|
||||||
}
|
}
|
||||||
|
@ -678,15 +631,15 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
||||||
frame.fn.LLVMFn = llvm.AddFunction(c.mod, name, fnType)
|
frame.fn.LLVMFn = llvm.AddFunction(c.mod, name, fnType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame, nil
|
return frame
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) attachDebugInfo(f *ir.Function) (llvm.Metadata, error) {
|
func (c *Compiler) attachDebugInfo(f *ir.Function) llvm.Metadata {
|
||||||
pos := c.ir.Program.Fset.Position(f.Syntax().Pos())
|
pos := c.ir.Program.Fset.Position(f.Syntax().Pos())
|
||||||
return c.attachDebugInfoRaw(f, f.LLVMFn, "", pos.Filename, pos.Line)
|
return c.attachDebugInfoRaw(f, f.LLVMFn, "", pos.Filename, pos.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix, filename string, line int) (llvm.Metadata, error) {
|
func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata {
|
||||||
if _, ok := c.difiles[filename]; !ok {
|
if _, ok := c.difiles[filename]; !ok {
|
||||||
dir, file := filepath.Split(filename)
|
dir, file := filepath.Split(filename)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
|
@ -698,11 +651,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
|
||||||
// Debug info for this function.
|
// Debug info for this function.
|
||||||
diparams := make([]llvm.Metadata, 0, len(f.Params))
|
diparams := make([]llvm.Metadata, 0, len(f.Params))
|
||||||
for _, param := range f.Params {
|
for _, param := range f.Params {
|
||||||
ditype, err := c.getDIType(param.Type())
|
diparams = append(diparams, c.getDIType(param.Type()))
|
||||||
if err != nil {
|
|
||||||
return llvm.Metadata{}, err
|
|
||||||
}
|
|
||||||
diparams = append(diparams, ditype)
|
|
||||||
}
|
}
|
||||||
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
||||||
File: c.difiles[filename],
|
File: c.difiles[filename],
|
||||||
|
@ -722,7 +671,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
|
||||||
Optimized: true,
|
Optimized: true,
|
||||||
})
|
})
|
||||||
llvmFn.SetSubprogram(difunc)
|
llvmFn.SetSubprogram(difunc)
|
||||||
return difunc, nil
|
return difunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseFunc(frame *Frame) error {
|
func (c *Compiler) parseFunc(frame *Frame) error {
|
||||||
|
@ -742,18 +691,10 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
||||||
if frame.fn.Synthetic == "package initializer" {
|
if frame.fn.Synthetic == "package initializer" {
|
||||||
// Package initializers have no debug info. Create some fake debug
|
// Package initializers have no debug info. Create some fake debug
|
||||||
// info to at least have *something*.
|
// info to at least have *something*.
|
||||||
difunc, err := c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
|
frame.difunc = c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
frame.difunc = difunc
|
|
||||||
} else if frame.fn.Syntax() != nil {
|
} else if frame.fn.Syntax() != nil {
|
||||||
// Create debug info file if needed.
|
// Create debug info file if needed.
|
||||||
difunc, err := c.attachDebugInfo(frame.fn)
|
frame.difunc = c.attachDebugInfo(frame.fn)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
frame.difunc = difunc
|
|
||||||
}
|
}
|
||||||
pos := c.ir.Program.Fset.Position(frame.fn.Pos())
|
pos := c.ir.Program.Fset.Position(frame.fn.Pos())
|
||||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{})
|
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{})
|
||||||
|
@ -771,10 +712,7 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
||||||
// Load function parameters
|
// Load function parameters
|
||||||
llvmParamIndex := 0
|
llvmParamIndex := 0
|
||||||
for i, param := range frame.fn.Params {
|
for i, param := range frame.fn.Params {
|
||||||
llvmType, err := c.getLLVMType(param.Type())
|
llvmType := c.getLLVMType(param.Type())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fields := make([]llvm.Value, 0, 1)
|
fields := make([]llvm.Value, 0, 1)
|
||||||
for range c.expandFormalParamType(llvmType) {
|
for range c.expandFormalParamType(llvmType) {
|
||||||
fields = append(fields, frame.fn.LLVMFn.Param(llvmParamIndex))
|
fields = append(fields, frame.fn.LLVMFn.Param(llvmParamIndex))
|
||||||
|
@ -785,15 +723,11 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
||||||
// Add debug information to this parameter (if available)
|
// Add debug information to this parameter (if available)
|
||||||
if c.Debug && frame.fn.Syntax() != nil {
|
if c.Debug && frame.fn.Syntax() != nil {
|
||||||
pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos())
|
pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos())
|
||||||
dityp, err := c.getDIType(param.Type())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
|
c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
|
||||||
Name: param.Name(),
|
Name: param.Name(),
|
||||||
File: c.difiles[pos.Filename],
|
File: c.difiles[pos.Filename],
|
||||||
Line: pos.Line,
|
Line: pos.Line,
|
||||||
Type: dityp,
|
Type: c.getDIType(param.Type()),
|
||||||
AlwaysPreserve: true,
|
AlwaysPreserve: true,
|
||||||
ArgNo: i + 1,
|
ArgNo: i + 1,
|
||||||
})
|
})
|
||||||
|
@ -814,11 +748,7 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
||||||
// Determine the context type. It's a struct containing all variables.
|
// Determine the context type. It's a struct containing all variables.
|
||||||
freeVarTypes := make([]llvm.Type, 0, len(frame.fn.FreeVars))
|
freeVarTypes := make([]llvm.Type, 0, len(frame.fn.FreeVars))
|
||||||
for _, freeVar := range frame.fn.FreeVars {
|
for _, freeVar := range frame.fn.FreeVars {
|
||||||
typ, err := c.getLLVMType(freeVar.Type())
|
freeVarTypes = append(freeVarTypes, c.getLLVMType(freeVar.Type()))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
freeVarTypes = append(freeVarTypes, typ)
|
|
||||||
}
|
}
|
||||||
contextType := c.ctx.StructType(freeVarTypes, false)
|
contextType := c.ctx.StructType(freeVarTypes, false)
|
||||||
|
|
||||||
|
@ -1346,10 +1276,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
|
|
||||||
switch expr := expr.(type) {
|
switch expr := expr.(type) {
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
typ, err := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
var buf llvm.Value
|
var buf llvm.Value
|
||||||
if expr.Heap {
|
if expr.Heap {
|
||||||
size := c.targetData.TypeAllocSize(typ)
|
size := c.targetData.TypeAllocSize(typ)
|
||||||
|
@ -1400,10 +1327,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
llvmType, err := c.getLLVMType(expr.Type())
|
llvmType := c.getLLVMType(expr.Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
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).
|
||||||
// This is the common case.
|
// This is the common case.
|
||||||
|
@ -1452,10 +1376,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// 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
|
||||||
// operation it's much easier to bitcast it through an alloca.
|
// operation it's much easier to bitcast it through an alloca.
|
||||||
resultType, err := c.getLLVMType(expr.Type())
|
resultType := c.getLLVMType(expr.Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
alloca := c.builder.CreateAlloca(value.Type(), "")
|
alloca := c.builder.CreateAlloca(value.Type(), "")
|
||||||
c.builder.CreateStore(value, alloca)
|
c.builder.CreateStore(value, alloca)
|
||||||
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "")
|
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "")
|
||||||
|
@ -1477,10 +1398,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// This is not a regular struct but actually an union.
|
// This is not a regular struct but actually an union.
|
||||||
// That simplifies things, as we can just bitcast the pointer to the
|
// That simplifies things, as we can just bitcast the pointer to the
|
||||||
// right type.
|
// right type.
|
||||||
ptrType, err := c.getLLVMType(expr.Type())
|
ptrType := c.getLLVMType(expr.Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, nil
|
|
||||||
}
|
|
||||||
return c.builder.CreateBitCast(val, ptrType, ""), nil
|
return c.builder.CreateBitCast(val, ptrType, ""), nil
|
||||||
} else {
|
} else {
|
||||||
// Do a GEP on the pointer to get the field address.
|
// Do a GEP on the pointer to get the field address.
|
||||||
|
@ -1495,7 +1413,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
if fn.IsExported() {
|
if fn.IsExported() {
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "cannot use an exported function as value")
|
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)
|
return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature), nil
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
value := c.ir.GetGlobal(expr).LLVMGlobal
|
value := c.ir.GetGlobal(expr).LLVMGlobal
|
||||||
if value.IsNil() {
|
if value.IsNil() {
|
||||||
|
@ -1620,14 +1538,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
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)
|
||||||
llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
|
llvmKeyType := c.getLLVMType(mapType.Key().Underlying())
|
||||||
if err != nil {
|
llvmValueType := c.getLLVMType(mapType.Elem().Underlying())
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
llvmValueType, err := c.getLLVMType(mapType.Elem().Underlying())
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
keySize := c.targetData.TypeAllocSize(llvmKeyType)
|
keySize := c.targetData.TypeAllocSize(llvmKeyType)
|
||||||
valueSize := c.targetData.TypeAllocSize(llvmValueType)
|
valueSize := c.targetData.TypeAllocSize(llvmValueType)
|
||||||
llvmKeySize := llvm.ConstInt(c.ctx.Int8Type(), keySize, false)
|
llvmKeySize := llvm.ConstInt(c.ctx.Int8Type(), keySize, false)
|
||||||
|
@ -1644,10 +1556,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
return llvm.Value{}, nil
|
return llvm.Value{}, nil
|
||||||
}
|
}
|
||||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||||
llvmElemType, err := c.getLLVMType(sliceType.Elem())
|
llvmElemType := c.getLLVMType(sliceType.Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, nil
|
|
||||||
}
|
|
||||||
elemSize := c.targetData.TypeAllocSize(llvmElemType)
|
elemSize := c.targetData.TypeAllocSize(llvmElemType)
|
||||||
elemSizeValue := llvm.ConstInt(c.uintptrType, elemSize, false)
|
elemSizeValue := llvm.ConstInt(c.uintptrType, elemSize, false)
|
||||||
|
|
||||||
|
@ -1707,14 +1616,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
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
|
||||||
llvmKeyType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||||
if err != nil {
|
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
llvmValueType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
|
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
|
||||||
mapKeyPtr := c.builder.CreateBitCast(mapKeyAlloca, c.i8ptrType, "range.keyptr")
|
mapKeyPtr := c.builder.CreateBitCast(mapKeyAlloca, c.i8ptrType, "range.keyptr")
|
||||||
|
@ -1729,11 +1632,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
return tuple, nil
|
return tuple, nil
|
||||||
}
|
}
|
||||||
case *ssa.Phi:
|
case *ssa.Phi:
|
||||||
t, err := c.getLLVMType(expr.Type())
|
phi := c.builder.CreatePHI(c.getLLVMType(expr.Type()), "")
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
phi := c.builder.CreatePHI(t, "")
|
|
||||||
frame.phis = append(frame.phis, Phi{expr, phi})
|
frame.phis = append(frame.phis, Phi{expr, phi})
|
||||||
return phi, nil
|
return phi, nil
|
||||||
case *ssa.Range:
|
case *ssa.Range:
|
||||||
|
@ -1752,10 +1651,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
case *ssa.Select:
|
case *ssa.Select:
|
||||||
if len(expr.States) == 0 {
|
if len(expr.States) == 0 {
|
||||||
// Shortcuts for some simple selects.
|
// Shortcuts for some simple selects.
|
||||||
llvmType, err := c.getLLVMType(expr.Type())
|
llvmType := c.getLLVMType(expr.Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
if expr.Blocking {
|
if expr.Blocking {
|
||||||
// Blocks forever:
|
// Blocks forever:
|
||||||
// select {}
|
// select {}
|
||||||
|
@ -2225,10 +2121,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, error) {
|
||||||
switch typ := expr.Type().Underlying().(type) {
|
switch typ := expr.Type().Underlying().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
llvmType, err := c.getLLVMType(typ)
|
llvmType := c.getLLVMType(typ)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
if typ.Info()&types.IsBoolean != 0 {
|
if typ.Info()&types.IsBoolean != 0 {
|
||||||
b := constant.BoolVal(expr.Value)
|
b := constant.BoolVal(expr.Value)
|
||||||
n := uint64(0)
|
n := uint64(0)
|
||||||
|
@ -2294,20 +2187,12 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
||||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||||
}
|
}
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
sig, err := c.getLLVMType(expr.Type())
|
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
return c.getZeroValue(sig), nil
|
|
||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
return llvm.Value{}, errors.New("non-nil signature constant")
|
return llvm.Value{}, errors.New("non-nil signature constant")
|
||||||
}
|
}
|
||||||
sig, err := c.getLLVMType(expr.Type())
|
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
return c.getZeroValue(sig), nil
|
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
return llvm.Value{}, errors.New("non-nil interface constant")
|
return llvm.Value{}, errors.New("non-nil interface constant")
|
||||||
|
@ -2323,19 +2208,12 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
return llvm.Value{}, errors.New("non-nil pointer constant")
|
return llvm.Value{}, errors.New("non-nil pointer constant")
|
||||||
}
|
}
|
||||||
llvmType, err := c.getLLVMType(typ)
|
return llvm.ConstPointerNull(c.getLLVMType(typ)), nil
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
return llvm.ConstPointerNull(llvmType), nil
|
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
if expr.Value != nil {
|
if expr.Value != nil {
|
||||||
return llvm.Value{}, errors.New("non-nil slice constant")
|
return llvm.Value{}, errors.New("non-nil slice constant")
|
||||||
}
|
}
|
||||||
elemType, err := c.getLLVMType(typ.Elem())
|
elemType := c.getLLVMType(typ.Elem())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
||||||
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := c.ctx.ConstStruct([]llvm.Value{
|
||||||
|
@ -2349,10 +2227,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
||||||
// 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, err := c.getLLVMType(typ)
|
llvmType := c.getLLVMType(typ)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
return c.getZeroValue(llvmType), nil
|
return c.getZeroValue(llvmType), nil
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||||
|
@ -2361,10 +2236,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
||||||
|
|
||||||
func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) {
|
func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) {
|
||||||
llvmTypeFrom := value.Type()
|
llvmTypeFrom := value.Type()
|
||||||
llvmTypeTo, err := c.getLLVMType(typeTo)
|
llvmTypeTo := c.getLLVMType(typeTo)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conversion between unsafe.Pointer and uintptr.
|
// Conversion between unsafe.Pointer and uintptr.
|
||||||
isPtrFrom := isPointer(typeFrom.Underlying())
|
isPtrFrom := isPointer(typeFrom.Underlying())
|
||||||
|
|
|
@ -217,11 +217,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0), c.i8ptrType}
|
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0), c.i8ptrType}
|
||||||
for _, arg := range callback.Args {
|
for _, arg := range callback.Args {
|
||||||
llvmType, err := c.getLLVMType(arg.Type())
|
valueTypes = append(valueTypes, c.getLLVMType(arg.Type()))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
valueTypes = append(valueTypes, llvmType)
|
|
||||||
}
|
}
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
@ -255,11 +251,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
||||||
// Get the real defer struct type and cast to it.
|
// Get the real defer struct type and cast to it.
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
||||||
for _, param := range callback.Params {
|
for _, param := range callback.Params {
|
||||||
llvmType, err := c.getLLVMType(param.Type())
|
valueTypes = append(valueTypes, c.getLLVMType(param.Type()))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
valueTypes = append(valueTypes, llvmType)
|
|
||||||
}
|
}
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||||
|
@ -289,11 +281,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
||||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
||||||
params := fn.Signature.Params()
|
params := fn.Signature.Params()
|
||||||
for i := 0; i < params.Len(); i++ {
|
for i := 0; i < params.Len(); i++ {
|
||||||
llvmType, err := c.getLLVMType(params.At(i).Type())
|
valueTypes = append(valueTypes, c.getLLVMType(params.At(i).Type()))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
valueTypes = append(valueTypes, llvmType)
|
|
||||||
}
|
}
|
||||||
valueTypes = append(valueTypes, c.i8ptrType) // closure
|
valueTypes = append(valueTypes, c.i8ptrType) // closure
|
||||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||||
|
|
|
@ -41,7 +41,7 @@ func (c *Compiler) funcImplementation() funcValueImplementation {
|
||||||
|
|
||||||
// createFuncValue creates a function value from a raw function pointer with no
|
// createFuncValue creates a function value from a raw function pointer with no
|
||||||
// context.
|
// context.
|
||||||
func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) (llvm.Value, error) {
|
func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
||||||
var funcValueScalar llvm.Value
|
var funcValueScalar llvm.Value
|
||||||
switch c.funcImplementation() {
|
switch c.funcImplementation() {
|
||||||
case funcValueDoubleword:
|
case funcValueDoubleword:
|
||||||
|
@ -66,14 +66,11 @@ func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signa
|
||||||
default:
|
default:
|
||||||
panic("unimplemented func value variant")
|
panic("unimplemented func value variant")
|
||||||
}
|
}
|
||||||
funcValueType, err := c.getFuncType(sig)
|
funcValueType := c.getFuncType(sig)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
funcValue := llvm.Undef(funcValueType)
|
funcValue := llvm.Undef(funcValueType)
|
||||||
funcValue = c.builder.CreateInsertValue(funcValue, context, 0, "")
|
funcValue = c.builder.CreateInsertValue(funcValue, context, 0, "")
|
||||||
funcValue = c.builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
|
funcValue = c.builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
|
||||||
return funcValue, nil
|
return funcValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFuncSignature returns a global for identification of a particular function
|
// getFuncSignature returns a global for identification of a particular function
|
||||||
|
@ -112,10 +109,7 @@ func (c *Compiler) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (
|
||||||
case funcValueDoubleword:
|
case funcValueDoubleword:
|
||||||
funcPtr = c.builder.CreateExtractValue(funcValue, 1, "")
|
funcPtr = c.builder.CreateExtractValue(funcValue, 1, "")
|
||||||
case funcValueSwitch:
|
case funcValueSwitch:
|
||||||
llvmSig, err := c.getRawFuncType(sig)
|
llvmSig := c.getRawFuncType(sig)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, llvm.Value{}, err
|
|
||||||
}
|
|
||||||
sigGlobal := c.getFuncSignature(sig)
|
sigGlobal := c.getFuncSignature(sig)
|
||||||
funcPtr = c.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
|
funcPtr = c.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
|
||||||
funcPtr = c.builder.CreateIntToPtr(funcPtr, llvmSig, "")
|
funcPtr = c.builder.CreateIntToPtr(funcPtr, llvmSig, "")
|
||||||
|
@ -126,25 +120,21 @@ func (c *Compiler) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFuncType returns the type of a func value given a signature.
|
// getFuncType returns the type of a func value given a signature.
|
||||||
func (c *Compiler) getFuncType(typ *types.Signature) (llvm.Type, error) {
|
func (c *Compiler) getFuncType(typ *types.Signature) llvm.Type {
|
||||||
switch c.funcImplementation() {
|
switch c.funcImplementation() {
|
||||||
case funcValueDoubleword:
|
case funcValueDoubleword:
|
||||||
rawPtr, err := c.getRawFuncType(typ)
|
rawPtr := c.getRawFuncType(typ)
|
||||||
if err != nil {
|
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false)
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false), nil
|
|
||||||
case funcValueSwitch:
|
case funcValueSwitch:
|
||||||
return c.mod.GetTypeByName("runtime.funcValue"), nil
|
return c.mod.GetTypeByName("runtime.funcValue")
|
||||||
default:
|
default:
|
||||||
panic("unimplemented func value variant")
|
panic("unimplemented func value variant")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRawFuncType returns a LLVM function pointer type for a given signature.
|
// getRawFuncType returns a LLVM function pointer type for a given signature.
|
||||||
func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
func (c *Compiler) getRawFuncType(typ *types.Signature) llvm.Type {
|
||||||
// Get the return type.
|
// Get the return type.
|
||||||
var err error
|
|
||||||
var returnType llvm.Type
|
var returnType llvm.Type
|
||||||
switch typ.Results().Len() {
|
switch typ.Results().Len() {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -152,21 +142,14 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||||
returnType = c.ctx.VoidType()
|
returnType = c.ctx.VoidType()
|
||||||
case 1:
|
case 1:
|
||||||
// Just one return value.
|
// Just one return value.
|
||||||
returnType, err = c.getLLVMType(typ.Results().At(0).Type())
|
returnType = c.getLLVMType(typ.Results().At(0).Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// Multiple return values. Put them together in a struct.
|
// Multiple return values. Put them together in a struct.
|
||||||
// This appears to be the common way to handle multiple return values in
|
// This appears to be the common way to handle multiple return values in
|
||||||
// LLVM.
|
// LLVM.
|
||||||
members := make([]llvm.Type, typ.Results().Len())
|
members := make([]llvm.Type, typ.Results().Len())
|
||||||
for i := 0; i < typ.Results().Len(); i++ {
|
for i := 0; i < typ.Results().Len(); i++ {
|
||||||
returnType, err := c.getLLVMType(typ.Results().At(i).Type())
|
members[i] = c.getLLVMType(typ.Results().At(i).Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
members[i] = returnType
|
|
||||||
}
|
}
|
||||||
returnType = c.ctx.StructType(members, false)
|
returnType = c.ctx.StructType(members, false)
|
||||||
}
|
}
|
||||||
|
@ -174,10 +157,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||||
// Get the parameter types.
|
// Get the parameter types.
|
||||||
var paramTypes []llvm.Type
|
var paramTypes []llvm.Type
|
||||||
if typ.Recv() != nil {
|
if typ.Recv() != nil {
|
||||||
recv, err := c.getLLVMType(typ.Recv().Type())
|
recv := c.getLLVMType(typ.Recv().Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
if recv.StructName() == "runtime._interface" {
|
if recv.StructName() == "runtime._interface" {
|
||||||
// This is a call on an interface, not a concrete type.
|
// This is a call on an interface, not a concrete type.
|
||||||
// The receiver is not an interface, but a i8* type.
|
// The receiver is not an interface, but a i8* type.
|
||||||
|
@ -186,10 +166,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||||
paramTypes = append(paramTypes, c.expandFormalParamType(recv)...)
|
paramTypes = append(paramTypes, c.expandFormalParamType(recv)...)
|
||||||
}
|
}
|
||||||
for i := 0; i < typ.Params().Len(); i++ {
|
for i := 0; i < typ.Params().Len(); i++ {
|
||||||
subType, err := c.getLLVMType(typ.Params().At(i).Type())
|
subType := c.getLLVMType(typ.Params().At(i).Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
paramTypes = append(paramTypes, c.expandFormalParamType(subType)...)
|
paramTypes = append(paramTypes, c.expandFormalParamType(subType)...)
|
||||||
}
|
}
|
||||||
// All functions take these parameters at the end.
|
// All functions take these parameters at the end.
|
||||||
|
@ -197,7 +174,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||||
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
|
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
|
||||||
|
|
||||||
// Make a func type out of the signature.
|
// Make a func type out of the signature.
|
||||||
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace), nil
|
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseMakeClosure makes a function value (with context) from the given
|
// parseMakeClosure makes a function value (with context) from the given
|
||||||
|
@ -261,5 +238,5 @@ func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.V
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the closure.
|
// Create the closure.
|
||||||
return c.createFuncValue(f.LLVMFn, context, f.Signature)
|
return c.createFuncValue(f.LLVMFn, context, f.Signature), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,10 +279,7 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
assertedType, err := c.getLLVMType(expr.AssertedType)
|
assertedType := c.getLLVMType(expr.AssertedType)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
|
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
|
||||||
commaOk := llvm.Value{}
|
commaOk := llvm.Value{}
|
||||||
|
@ -389,10 +386,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu
|
||||||
return llvm.Value{}, nil, err
|
return llvm.Value{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
llvmFnType, err := c.getRawFuncType(instr.Method.Type().(*types.Signature))
|
llvmFnType := c.getRawFuncType(instr.Method.Type().(*types.Signature))
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode")
|
typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode")
|
||||||
values := []llvm.Value{
|
values := []llvm.Value{
|
||||||
|
@ -443,10 +437,7 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the expanded receiver type.
|
// Get the expanded receiver type.
|
||||||
receiverType, err := c.getLLVMType(f.Params[0].Type())
|
receiverType := c.getLLVMType(f.Params[0].Type())
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
expandedReceiverType := c.expandFormalParamType(receiverType)
|
expandedReceiverType := c.expandFormalParamType(receiverType)
|
||||||
|
|
||||||
// Does this method even need any wrapping?
|
// Does this method even need any wrapping?
|
||||||
|
@ -473,7 +464,7 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error)
|
||||||
|
|
||||||
// createInterfaceInvokeWrapper finishes the work of getInterfaceInvokeWrapper,
|
// createInterfaceInvokeWrapper finishes the work of getInterfaceInvokeWrapper,
|
||||||
// see that function for details.
|
// see that function for details.
|
||||||
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) error {
|
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) {
|
||||||
wrapper := state.wrapper
|
wrapper := state.wrapper
|
||||||
fn := state.fn
|
fn := state.fn
|
||||||
receiverType := state.receiverType
|
receiverType := state.receiverType
|
||||||
|
@ -483,10 +474,7 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er
|
||||||
// add debug info if needed
|
// add debug info if needed
|
||||||
if c.Debug {
|
if c.Debug {
|
||||||
pos := c.ir.Program.Fset.Position(fn.Pos())
|
pos := c.ir.Program.Fset.Position(fn.Pos())
|
||||||
difunc, err := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
|
difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,6 +512,4 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er
|
||||||
ret := c.builder.CreateCall(fn.LLVMFn, params, "ret")
|
ret := c.builder.CreateCall(fn.LLVMFn, params, "ret")
|
||||||
c.builder.CreateRet(ret)
|
c.builder.CreateRet(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
|
func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
|
||||||
llvmValueType, err := c.getLLVMType(valueType)
|
llvmValueType := c.getLLVMType(valueType)
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
|
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
|
||||||
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
|
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
|
||||||
var commaOkValue llvm.Value
|
var commaOkValue llvm.Value
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче