Browse Source

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.
pull/318/head
Ayke van Laethem 6 years ago
committed by Ron Evans
parent
commit
c25fe609a9
  1. 20
      compiler/channel.go
  2. 274
      compiler/compiler.go
  3. 18
      compiler/defer.go
  4. 53
      compiler/func.go
  5. 24
      compiler/interface.go
  6. 5
      compiler/map.go

20
compiler/channel.go

@ -12,10 +12,7 @@ import (
// emitMakeChan returns a new channel value for the given channel type.
func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
valueType, err := c.getLLVMType(expr.Type().(*types.Chan).Elem())
if err != nil {
return llvm.Value{}, err
}
valueType := c.getLLVMType(expr.Type().(*types.Chan).Elem())
if c.targetData.TypeAllocSize(valueType) > c.targetData.TypeAllocSize(c.intType) {
// Values bigger than int overflow the data part of the coroutine.
// 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
// channel send operation during goroutine lowering.
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error {
valueType, err := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
if err != nil {
return err
}
valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
ch, err := c.parseExpr(frame, instr.Chan)
if err != nil {
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
// actual channel receive operation during goroutine lowering.
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
valueType, err := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
if err != nil {
return llvm.Value{}, err
}
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
ch, err := c.parseExpr(frame, unop.X)
if err != nil {
@ -83,11 +74,8 @@ func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error
// emitChanClose closes the given channel.
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)
if err != nil {
return err
}
ch, err := c.parseExpr(frame, param)
if err != nil {
return err

274
compiler/compiler.go

@ -274,10 +274,7 @@ func (c *Compiler) Compile(mainPath string) error {
for _, t := range c.ir.NamedTypes {
if named, ok := t.Type.Type().(*types.Named); ok {
if st, ok := named.Underlying().(*types.Struct); ok {
llvmType, err := c.getLLVMType(st)
if err != nil {
return err
}
llvmType := c.getLLVMType(st)
t.LLVMType.StructSetBody(llvmType.StructElementTypes(), false)
}
}
@ -286,10 +283,7 @@ func (c *Compiler) Compile(mainPath string) error {
// Declare all globals.
for _, g := range c.ir.Globals {
typ := g.Type().(*types.Pointer).Elem()
llvmType, err := c.getLLVMType(typ)
if err != nil {
return err
}
llvmType := c.getLLVMType(typ)
global := c.mod.NamedGlobal(g.LinkName())
if global.IsNil() {
global = llvm.AddGlobal(c.mod, llvmType, g.LinkName())
@ -303,11 +297,7 @@ func (c *Compiler) Compile(mainPath string) error {
// Declare all functions.
for _, f := range c.ir.Functions {
frame, err := c.parseFuncDecl(f)
if err != nil {
return err
}
frames = append(frames, frame)
frames = append(frames, c.parseFuncDecl(f))
}
// 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
// interfaces.
for _, state := range c.interfaceInvokeWrappers {
err = c.createInterfaceInvokeWrapper(state)
if err != nil {
return err
}
c.createInterfaceInvokeWrapper(state)
}
// 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.SetUnnamedAddr(true)
if c.Debug {
difunc, err := c.attachDebugInfo(initFn)
if err != nil {
return err
}
difunc := c.attachDebugInfo(initFn)
pos := c.ir.Program.Fset.Position(initFn.Pos())
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
}
func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
func (c *Compiler) getLLVMType(goType types.Type) llvm.Type {
switch typ := goType.(type) {
case *types.Array:
elemType, err := c.getLLVMType(typ.Elem())
if err != nil {
return llvm.Type{}, err
}
return llvm.ArrayType(elemType, int(typ.Len())), nil
elemType := c.getLLVMType(typ.Elem())
return llvm.ArrayType(elemType, int(typ.Len()))
case *types.Basic:
switch typ.Kind() {
case types.Bool, types.UntypedBool:
return c.ctx.Int1Type(), nil
return c.ctx.Int1Type()
case types.Int8, types.Uint8:
return c.ctx.Int8Type(), nil
return c.ctx.Int8Type()
case types.Int16, types.Uint16:
return c.ctx.Int16Type(), nil
return c.ctx.Int16Type()
case types.Int32, types.Uint32:
return c.ctx.Int32Type(), nil
return c.ctx.Int32Type()
case types.Int, types.Uint:
return c.intType, nil
return c.intType
case types.Int64, types.Uint64:
return c.ctx.Int64Type(), nil
return c.ctx.Int64Type()
case types.Float32:
return c.ctx.FloatType(), nil
return c.ctx.FloatType()
case types.Float64:
return c.ctx.DoubleType(), nil
return c.ctx.DoubleType()
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:
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:
return c.mod.GetTypeByName("runtime._string"), nil
return c.mod.GetTypeByName("runtime._string")
case types.Uintptr:
return c.uintptrType, nil
return c.uintptrType
case types.UnsafePointer:
return c.i8ptrType, nil
return c.i8ptrType
default:
return llvm.Type{}, errors.New("todo: unknown basic type: " + typ.String())
panic("unknown basic type: " + typ.String())
}
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:
return c.mod.GetTypeByName("runtime._interface"), nil
return c.mod.GetTypeByName("runtime._interface")
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:
if _, ok := typ.Underlying().(*types.Struct); ok {
llvmType := c.mod.GetTypeByName(typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
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())
case *types.Pointer:
ptrTo, err := c.getLLVMType(typ.Elem())
if err != nil {
return llvm.Type{}, err
}
return llvm.PointerType(ptrTo, 0), nil
ptrTo := c.getLLVMType(typ.Elem())
return llvm.PointerType(ptrTo, 0)
case *types.Signature: // function value
return c.getFuncType(typ)
case *types.Slice:
elemType, err := c.getLLVMType(typ.Elem())
if err != nil {
return llvm.Type{}, err
}
elemType := c.getLLVMType(typ.Elem())
members := []llvm.Type{
llvm.PointerType(elemType, 0),
c.uintptrType, // len
c.uintptrType, // cap
}
return c.ctx.StructType(members, false), nil
return c.ctx.StructType(members, false)
case *types.Struct:
members := make([]llvm.Type, typ.NumFields())
for i := 0; i < typ.NumFields(); i++ {
member, err := c.getLLVMType(typ.Field(i).Type())
if err != nil {
return llvm.Type{}, err
}
members[i] = member
members[i] = c.getLLVMType(typ.Field(i).Type())
}
if len(members) > 2 && typ.Field(0).Name() == "C union" {
// 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)))
}
}
return c.ctx.StructType(members, false), nil
return c.ctx.StructType(members, false)
case *types.Tuple:
members := make([]llvm.Type, typ.Len())
for i := 0; i < typ.Len(); i++ {
member, err := c.getLLVMType(typ.At(i).Type())
if err != nil {
return llvm.Type{}, err
}
members[i] = member
members[i] = c.getLLVMType(typ.At(i).Type())
}
return c.ctx.StructType(members, false), nil
return c.ctx.StructType(members, false)
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.
func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
func (c *Compiler) getDIType(typ types.Type) llvm.Metadata {
name := typ.String()
if dityp, ok := c.ditypes[name]; ok {
return dityp, nil
return dityp
} else {
llvmType, err := c.getLLVMType(typ)
if err != nil {
return llvm.Metadata{}, err
}
llvmType := c.getLLVMType(typ)
sizeInBytes := c.targetData.TypeAllocSize(llvmType)
var encoding llvm.DwarfTypeEncoding
switch typ := typ.(type) {
@ -620,11 +584,11 @@ func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
Encoding: encoding,
})
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{
fn: f,
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 {
retType = c.ctx.VoidType()
} else if f.Signature.Results().Len() == 1 {
var err error
retType, err = c.getLLVMType(f.Signature.Results().At(0).Type())
if err != nil {
return nil, err
}
retType = c.getLLVMType(f.Signature.Results().At(0).Type())
} else {
results := make([]llvm.Type, 0, f.Signature.Results().Len())
for i := 0; i < f.Signature.Results().Len(); i++ {
typ, err := c.getLLVMType(f.Signature.Results().At(i).Type())
if err != nil {
return nil, err
}
results = append(results, typ)
results = append(results, c.getLLVMType(f.Signature.Results().At(i).Type()))
}
retType = c.ctx.StructType(results, false)
}
var paramTypes []llvm.Type
for _, param := range f.Params {
paramType, err := c.getLLVMType(param.Type())
if err != nil {
return nil, err
}
paramType := c.getLLVMType(param.Type())
paramTypeFragments := c.expandFormalParamType(paramType)
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)
}
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())
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 {
dir, file := filepath.Split(filename)
if dir != "" {
@ -698,11 +651,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
// Debug info for this function.
diparams := make([]llvm.Metadata, 0, len(f.Params))
for _, param := range f.Params {
ditype, err := c.getDIType(param.Type())
if err != nil {
return llvm.Metadata{}, err
}
diparams = append(diparams, ditype)
diparams = append(diparams, c.getDIType(param.Type()))
}
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: c.difiles[filename],
@ -722,7 +671,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
Optimized: true,
})
llvmFn.SetSubprogram(difunc)
return difunc, nil
return difunc
}
func (c *Compiler) parseFunc(frame *Frame) error {
@ -742,18 +691,10 @@ func (c *Compiler) parseFunc(frame *Frame) error {
if frame.fn.Synthetic == "package initializer" {
// Package initializers have no debug info. Create some fake debug
// info to at least have *something*.
difunc, err := c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
if err != nil {
return err
}
frame.difunc = difunc
frame.difunc = c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
} else if frame.fn.Syntax() != nil {
// Create debug info file if needed.
difunc, err := c.attachDebugInfo(frame.fn)
if err != nil {
return err
}
frame.difunc = difunc
frame.difunc = c.attachDebugInfo(frame.fn)
}
pos := c.ir.Program.Fset.Position(frame.fn.Pos())
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
llvmParamIndex := 0
for i, param := range frame.fn.Params {
llvmType, err := c.getLLVMType(param.Type())
if err != nil {
return err
}
llvmType := c.getLLVMType(param.Type())
fields := make([]llvm.Value, 0, 1)
for range c.expandFormalParamType(llvmType) {
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)
if c.Debug && frame.fn.Syntax() != nil {
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{
Name: param.Name(),
File: c.difiles[pos.Filename],
Line: pos.Line,
Type: dityp,
Type: c.getDIType(param.Type()),
AlwaysPreserve: true,
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.
freeVarTypes := make([]llvm.Type, 0, len(frame.fn.FreeVars))
for _, freeVar := range frame.fn.FreeVars {
typ, err := c.getLLVMType(freeVar.Type())
if err != nil {
return err
}
freeVarTypes = append(freeVarTypes, typ)
freeVarTypes = append(freeVarTypes, c.getLLVMType(freeVar.Type()))
}
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) {
case *ssa.Alloc:
typ, err := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
if err != nil {
return llvm.Value{}, err
}
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
var buf llvm.Value
if expr.Heap {
size := c.targetData.TypeAllocSize(typ)
@ -1400,10 +1327,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
if err != nil {
return llvm.Value{}, err
}
llvmType, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
llvmType := c.getLLVMType(expr.Type())
if x.Type() == llvmType {
// Different Go type but same LLVM type (for example, named int).
// 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.
// This could be done directly, but as this is a very infrequent
// operation it's much easier to bitcast it through an alloca.
resultType, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
resultType := c.getLLVMType(expr.Type())
alloca := c.builder.CreateAlloca(value.Type(), "")
c.builder.CreateStore(value, alloca)
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.
// That simplifies things, as we can just bitcast the pointer to the
// right type.
ptrType, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, nil
}
ptrType := c.getLLVMType(expr.Type())
return c.builder.CreateBitCast(val, ptrType, ""), nil
} else {
// 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() {
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:
value := c.ir.GetGlobal(expr).LLVMGlobal
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())
case *ssa.MakeMap:
mapType := expr.Type().Underlying().(*types.Map)
llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
if err != nil {
return llvm.Value{}, err
}
llvmValueType, err := c.getLLVMType(mapType.Elem().Underlying())
if err != nil {
return llvm.Value{}, err
}
llvmKeyType := c.getLLVMType(mapType.Key().Underlying())
llvmValueType := c.getLLVMType(mapType.Elem().Underlying())
keySize := c.targetData.TypeAllocSize(llvmKeyType)
valueSize := c.targetData.TypeAllocSize(llvmValueType)
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
}
sliceType := expr.Type().Underlying().(*types.Slice)
llvmElemType, err := c.getLLVMType(sliceType.Elem())
if err != nil {
return llvm.Value{}, nil
}
llvmElemType := c.getLLVMType(sliceType.Elem())
elemSize := c.targetData.TypeAllocSize(llvmElemType)
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 {
return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
} else { // map
llvmKeyType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
if err != nil {
return llvm.Value{}, err
}
llvmValueType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
if err != nil {
return llvm.Value{}, err
}
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
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
}
case *ssa.Phi:
t, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
phi := c.builder.CreatePHI(t, "")
phi := c.builder.CreatePHI(c.getLLVMType(expr.Type()), "")
frame.phis = append(frame.phis, Phi{expr, phi})
return phi, nil
case *ssa.Range:
@ -1752,10 +1651,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
case *ssa.Select:
if len(expr.States) == 0 {
// Shortcuts for some simple selects.
llvmType, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
llvmType := c.getLLVMType(expr.Type())
if expr.Blocking {
// Blocks forever:
// 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) {
switch typ := expr.Type().Underlying().(type) {
case *types.Basic:
llvmType, err := c.getLLVMType(typ)
if err != nil {
return llvm.Value{}, err
}
llvmType := c.getLLVMType(typ)
if typ.Info()&types.IsBoolean != 0 {
b := constant.BoolVal(expr.Value)
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())
}
case *types.Chan:
sig, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
return c.getZeroValue(sig), nil
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
case *types.Signature:
if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil signature constant")
}
sig, err := c.getLLVMType(expr.Type())
if err != nil {
return llvm.Value{}, err
}
return c.getZeroValue(sig), nil
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
case *types.Interface:
if expr.Value != nil {
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 {
return llvm.Value{}, errors.New("non-nil pointer constant")
}
llvmType, err := c.getLLVMType(typ)
if err != nil {
return llvm.Value{}, err
}
return llvm.ConstPointerNull(llvmType), nil
return llvm.ConstPointerNull(c.getLLVMType(typ)), nil
case *types.Slice:
if expr.Value != nil {
return llvm.Value{}, errors.New("non-nil slice constant")
}
elemType, err := c.getLLVMType(typ.Elem())
if err != nil {
return llvm.Value{}, err
}
elemType := c.getLLVMType(typ.Elem())
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
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.
panic("non-nil map constant")
}
llvmType, err := c.getLLVMType(typ)
if err != nil {
return llvm.Value{}, err
}
llvmType := c.getLLVMType(typ)
return c.getZeroValue(llvmType), nil
default:
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) {
llvmTypeFrom := value.Type()
llvmTypeTo, err := c.getLLVMType(typeTo)
if err != nil {
return llvm.Value{}, err
}
llvmTypeTo := c.getLLVMType(typeTo)
// Conversion between unsafe.Pointer and uintptr.
isPtrFrom := isPointer(typeFrom.Underlying())

18
compiler/defer.go

@ -217,11 +217,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
// 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}
for _, arg := range callback.Args {
llvmType, err := c.getLLVMType(arg.Type())
if err != nil {
return err
}
valueTypes = append(valueTypes, llvmType)
valueTypes = append(valueTypes, c.getLLVMType(arg.Type()))
}
deferFrameType := c.ctx.StructType(valueTypes, false)
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.
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
for _, param := range callback.Params {
llvmType, err := c.getLLVMType(param.Type())
if err != nil {
return err
}
valueTypes = append(valueTypes, llvmType)
valueTypes = append(valueTypes, c.getLLVMType(param.Type()))
}
deferFrameType := c.ctx.StructType(valueTypes, false)
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)}
params := fn.Signature.Params()
for i := 0; i < params.Len(); i++ {
llvmType, err := c.getLLVMType(params.At(i).Type())
if err != nil {
return err
}
valueTypes = append(valueTypes, llvmType)
valueTypes = append(valueTypes, c.getLLVMType(params.At(i).Type()))
}
valueTypes = append(valueTypes, c.i8ptrType) // closure
deferFrameType := c.ctx.StructType(valueTypes, false)

53
compiler/func.go

@ -41,7 +41,7 @@ func (c *Compiler) funcImplementation() funcValueImplementation {
// createFuncValue creates a function value from a raw function pointer with no
// 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
switch c.funcImplementation() {
case funcValueDoubleword:
@ -66,14 +66,11 @@ func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signa
default:
panic("unimplemented func value variant")
}
funcValueType, err := c.getFuncType(sig)
if err != nil {
return llvm.Value{}, err
}
funcValueType := c.getFuncType(sig)
funcValue := llvm.Undef(funcValueType)
funcValue = c.builder.CreateInsertValue(funcValue, context, 0, "")
funcValue = c.builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
return funcValue, nil
return funcValue
}
// 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:
funcPtr = c.builder.CreateExtractValue(funcValue, 1, "")
case funcValueSwitch:
llvmSig, err := c.getRawFuncType(sig)
if err != nil {
return llvm.Value{}, llvm.Value{}, err
}
llvmSig := c.getRawFuncType(sig)
sigGlobal := c.getFuncSignature(sig)
funcPtr = c.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
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.
func (c *Compiler) getFuncType(typ *types.Signature) (llvm.Type, error) {
func (c *Compiler) getFuncType(typ *types.Signature) llvm.Type {
switch c.funcImplementation() {
case funcValueDoubleword:
rawPtr, err := c.getRawFuncType(typ)
if err != nil {
return llvm.Type{}, err
}
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false), nil
rawPtr := c.getRawFuncType(typ)
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false)
case funcValueSwitch:
return c.mod.GetTypeByName("runtime.funcValue"), nil
return c.mod.GetTypeByName("runtime.funcValue")
default:
panic("unimplemented func value variant")
}
}
// 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.
var err error
var returnType llvm.Type
switch typ.Results().Len() {
case 0:
@ -152,21 +142,14 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
returnType = c.ctx.VoidType()
case 1:
// Just one return value.
returnType, err = c.getLLVMType(typ.Results().At(0).Type())
if err != nil {
return llvm.Type{}, err
}
returnType = c.getLLVMType(typ.Results().At(0).Type())
default:
// Multiple return values. Put them together in a struct.
// This appears to be the common way to handle multiple return values in
// LLVM.
members := make([]llvm.Type, typ.Results().Len())
for i := 0; i < typ.Results().Len(); i++ {
returnType, err := c.getLLVMType(typ.Results().At(i).Type())
if err != nil {
return llvm.Type{}, err
}
members[i] = returnType
members[i] = c.getLLVMType(typ.Results().At(i).Type())
}
returnType = c.ctx.StructType(members, false)
}
@ -174,10 +157,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
// Get the parameter types.
var paramTypes []llvm.Type
if typ.Recv() != nil {
recv, err := c.getLLVMType(typ.Recv().Type())
if err != nil {
return llvm.Type{}, err
}
recv := c.getLLVMType(typ.Recv().Type())
if recv.StructName() == "runtime._interface" {
// This is a call on an interface, not a concrete 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)...)
}
for i := 0; i < typ.Params().Len(); i++ {
subType, err := c.getLLVMType(typ.Params().At(i).Type())
if err != nil {
return llvm.Type{}, err
}
subType := c.getLLVMType(typ.Params().At(i).Type())
paramTypes = append(paramTypes, c.expandFormalParamType(subType)...)
}
// 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
// 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
@ -261,5 +238,5 @@ func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.V
}
// Create the closure.
return c.createFuncValue(f.LLVMFn, context, f.Signature)
return c.createFuncValue(f.LLVMFn, context, f.Signature), nil
}

24
compiler/interface.go

@ -279,10 +279,7 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val
if err != nil {
return llvm.Value{}, err
}
assertedType, err := c.getLLVMType(expr.AssertedType)
if err != nil {
return llvm.Value{}, err
}
assertedType := c.getLLVMType(expr.AssertedType)
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
commaOk := llvm.Value{}
@ -389,10 +386,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu
return llvm.Value{}, nil, err
}
llvmFnType, err := c.getRawFuncType(instr.Method.Type().(*types.Signature))
if err != nil {
return llvm.Value{}, nil, err
}
llvmFnType := c.getRawFuncType(instr.Method.Type().(*types.Signature))
typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode")
values := []llvm.Value{
@ -443,10 +437,7 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error)
}
// Get the expanded receiver type.
receiverType, err := c.getLLVMType(f.Params[0].Type())
if err != nil {
return llvm.Value{}, err
}
receiverType := c.getLLVMType(f.Params[0].Type())
expandedReceiverType := c.expandFormalParamType(receiverType)
// 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,
// see that function for details.
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) error {
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) {
wrapper := state.wrapper
fn := state.fn
receiverType := state.receiverType
@ -483,10 +474,7 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er
// add debug info if needed
if c.Debug {
pos := c.ir.Program.Fset.Position(fn.Pos())
difunc, err := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
if err != nil {
return err
}
difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
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")
c.builder.CreateRet(ret)
}
return nil
}

5
compiler/map.go

@ -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) {
llvmValueType, err := c.getLLVMType(valueType)
if err != nil {
return llvm.Value{}, err
}
llvmValueType := c.getLLVMType(valueType)
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
var commaOkValue llvm.Value

Loading…
Cancel
Save