diff --git a/compiler/calls.go b/compiler/calls.go index 2ac293ba17..b5296f91a2 100644 --- a/compiler/calls.go +++ b/compiler/calls.go @@ -123,10 +123,7 @@ func (c *Compiler) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) switch t.TypeKind() { case llvm.StructTypeKind: if len(c.flattenAggregateType(t)) <= MaxFieldsPerParam { - value, err := c.getZeroValue(t) - if err != nil { - panic("could not get zero value of struct: " + err.Error()) - } + value := c.getZeroValue(t) for i, subtyp := range t.StructElementTypes() { structField, remaining := c.collapseFormalParamInternal(subtyp, fields) fields = remaining diff --git a/compiler/channel.go b/compiler/channel.go index 05973ecbfc..d9ab1b8499 100644 --- a/compiler/channel.go +++ b/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 @@ -32,39 +29,23 @@ func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) { // emitChanSend emits a pseudo chan send operation. It is lowered to the actual // channel send operation during goroutine lowering. -func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error { - valueType, err := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem()) - if err != nil { - return err - } - ch, err := c.parseExpr(frame, instr.Chan) - if err != nil { - return err - } - chanValue, err := c.parseExpr(frame, instr.X) - if err != nil { - return err - } +func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) { + valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem()) + ch := c.getValue(frame, instr.Chan) + chanValue := c.getValue(frame, instr.X) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false) valueAlloca := c.builder.CreateAlloca(valueType, "chan.value") c.builder.CreateStore(chanValue, valueAlloca) valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr") c.createRuntimeCall("chanSendStub", []llvm.Value{llvm.Undef(c.i8ptrType), ch, valueAllocaCast, valueSize}, "") - return nil } // emitChanRecv emits a pseudo chan receive operation. It is lowered to the // actual channel receive operation during goroutine lowering. -func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { - valueType, err := c.getLLVMType(unop.X.Type().(*types.Chan).Elem()) - if err != nil { - return llvm.Value{}, err - } +func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value { + valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem()) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false) - ch, err := c.parseExpr(frame, unop.X) - if err != nil { - return llvm.Value{}, err - } + ch := c.getValue(frame, unop.X) valueAlloca := c.builder.CreateAlloca(valueType, "chan.value") valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr") valueOk := c.builder.CreateAlloca(c.ctx.Int1Type(), "chan.comma-ok.alloca") @@ -75,23 +56,16 @@ func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{valueType, c.ctx.Int1Type()}, false)) tuple = c.builder.CreateInsertValue(tuple, received, 0, "") tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") - return tuple, nil + return tuple } else { - return received, nil + return received } } // emitChanClose closes the given channel. -func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) error { - valueType, err := c.getLLVMType(param.Type().(*types.Chan).Elem()) +func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) { + valueType := c.getLLVMType(param.Type().(*types.Chan).Elem()) valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false) - if err != nil { - return err - } - ch, err := c.parseExpr(frame, param) - if err != nil { - return err - } + ch := c.getValue(frame, param) c.createRuntimeCall("chanClose", []llvm.Value{ch, valueSize}, "") - return nil } diff --git a/compiler/compiler.go b/compiler/compiler.go index 4c686556ea..c00e0269a3 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -61,6 +61,7 @@ type Compiler struct { initFuncs []llvm.Value interfaceInvokeWrappers []interfaceInvokeWrapper ir *ir.Program + diagnostics []error } type Frame struct { @@ -158,7 +159,7 @@ func (c *Compiler) selectGC() string { // Compile the given package path or .go file path. Return an error when this // fails (in any stage). -func (c *Compiler) Compile(mainPath string) error { +func (c *Compiler) Compile(mainPath string) []error { // Prefix the GOPATH with the system GOROOT, as GOROOT is already set to // the TinyGo root. overlayGopath := c.GOPATH @@ -170,7 +171,7 @@ func (c *Compiler) Compile(mainPath string) error { wd, err := os.Getwd() if err != nil { - return err + return []error{err} } lprogram := &loader.Program{ Build: &build.Context{ @@ -223,22 +224,22 @@ func (c *Compiler) Compile(mainPath string) error { if strings.HasSuffix(mainPath, ".go") { _, err = lprogram.ImportFile(mainPath) if err != nil { - return err + return []error{err} } } else { _, err = lprogram.Import(mainPath, wd) if err != nil { - return err + return []error{err} } } _, err = lprogram.Import("runtime", "") if err != nil { - return err + return []error{err} } err = lprogram.Parse() if err != nil { - return err + return []error{err} } c.ir = ir.NewProgram(lprogram, mainPath) @@ -272,10 +273,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) } } @@ -284,10 +282,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()) @@ -295,21 +290,13 @@ func (c *Compiler) Compile(mainPath string) error { g.LLVMGlobal = global if !g.IsExtern() { global.SetLinkage(llvm.InternalLinkage) - initializer, err := c.getZeroValue(llvmType) - if err != nil { - return err - } - global.SetInitializer(initializer) + global.SetInitializer(c.getZeroValue(llvmType)) } } // 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. @@ -323,19 +310,13 @@ func (c *Compiler) Compile(mainPath string) error { if frame.fn.Blocks == nil { continue // external function } - err := c.parseFunc(frame) - if err != nil { - return err - } + c.parseFunc(frame) } // 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 @@ -344,10 +325,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{}) } @@ -410,90 +388,77 @@ func (c *Compiler) Compile(mainPath string) error { c.dibuilder.Finalize() } - return nil + return c.diagnostics } -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. @@ -522,19 +487,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()) } } @@ -542,42 +503,35 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) { // initializer has the same effect as setting 'zeroinitializer' on a value. // Sadly, I haven't found a way to do it directly with the Go API but this works // just fine. -func (c *Compiler) getZeroValue(typ llvm.Type) (llvm.Value, error) { +func (c *Compiler) getZeroValue(typ llvm.Type) llvm.Value { switch typ.TypeKind() { case llvm.ArrayTypeKind: subTyp := typ.ElementType() - subVal, err := c.getZeroValue(subTyp) - if err != nil { - return llvm.Value{}, err - } + subVal := c.getZeroValue(subTyp) vals := make([]llvm.Value, typ.ArrayLength()) for i := range vals { vals[i] = subVal } - return llvm.ConstArray(subTyp, vals), nil + return llvm.ConstArray(subTyp, vals) case llvm.FloatTypeKind, llvm.DoubleTypeKind: - return llvm.ConstFloat(typ, 0.0), nil + return llvm.ConstFloat(typ, 0.0) case llvm.IntegerTypeKind: - return llvm.ConstInt(typ, 0, false), nil + return llvm.ConstInt(typ, 0, false) case llvm.PointerTypeKind: - return llvm.ConstPointerNull(typ), nil + return llvm.ConstPointerNull(typ) case llvm.StructTypeKind: types := typ.StructElementTypes() vals := make([]llvm.Value, len(types)) for i, subTyp := range types { - val, err := c.getZeroValue(subTyp) - if err != nil { - return llvm.Value{}, err - } - vals[i] = val + vals[i] = c.getZeroValue(subTyp) } if typ.StructName() != "" { - return llvm.ConstNamedStruct(typ, vals), nil + return llvm.ConstNamedStruct(typ, vals) } else { - return c.ctx.ConstStruct(vals, false), nil + return c.ctx.ConstStruct(vals, false) } default: - return llvm.Value{}, errors.New("todo: LLVM zero initializer: " + typ.String()) + panic("unknown LLVM zero inititializer: " + typ.String()) } } @@ -593,15 +547,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) { @@ -629,11 +580,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), @@ -645,29 +596,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...) } @@ -687,15 +627,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 != "" { @@ -707,11 +647,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], @@ -731,10 +667,10 @@ 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 { +func (c *Compiler) parseFunc(frame *Frame) { if c.DumpSSA { fmt.Printf("\nfunc %s:\n", frame.fn.Function) } @@ -751,18 +687,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{}) @@ -780,10 +708,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)) @@ -794,15 +719,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, }) @@ -823,11 +744,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) @@ -883,10 +800,7 @@ func (c *Compiler) parseFunc(frame *Frame) error { fmt.Printf("\t%s\n", instr.String()) } } - err := c.parseInstr(frame, instr) - if err != nil { - return err - } + c.parseInstr(frame, instr) } if frame.fn.Name() == "init" && len(block.Instrs) == 0 { c.builder.CreateRetVoid() @@ -897,19 +811,14 @@ func (c *Compiler) parseFunc(frame *Frame) error { for _, phi := range frame.phis { block := phi.ssa.Block() for i, edge := range phi.ssa.Edges { - llvmVal, err := c.parseExpr(frame, edge) - if err != nil { - return err - } + llvmVal := c.getValue(frame, edge) llvmBlock := frame.blockExits[block.Preds[i]] phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock}) } } - - return nil } -func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { +func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) { if c.Debug { pos := c.ir.Program.Fset.Position(instr.Pos()) c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{}) @@ -917,20 +826,31 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { switch instr := instr.(type) { case ssa.Value: - value, err := c.parseExpr(frame, instr) - frame.locals[instr] = value - return err + if value, err := c.parseExpr(frame, instr); err != nil { + // This expression could not be parsed. Add the error to the list + // of diagnostics and continue with an undef value. + // The resulting IR will be incorrect (but valid). However, + // compilation can proceed which is useful because there may be + // more compilation errors which can then all be shown together to + // the user. + c.diagnostics = append(c.diagnostics, err) + frame.locals[instr] = llvm.Undef(c.getLLVMType(instr.Type())) + } else { + frame.locals[instr] = value + } case *ssa.DebugRef: - return nil // ignore + // ignore case *ssa.Defer: - return c.emitDefer(frame, instr) + c.emitDefer(frame, instr) case *ssa.Go: if instr.Call.IsInvoke() { - return c.makeError(instr.Pos(), "todo: go on method receiver") + c.addError(instr.Pos(), "todo: go on method receiver") + return } callee := instr.Call.StaticCallee() if callee == nil { - return c.makeError(instr.Pos(), "todo: go on non-direct function (function pointer, etc.)") + c.addError(instr.Pos(), "todo: go on non-direct function (function pointer, etc.)") + return } calleeFn := c.ir.GetFunction(callee) @@ -945,11 +865,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { // Get all function parameters to pass to the goroutine. var params []llvm.Value for _, param := range instr.Call.Args { - val, err := c.parseExpr(frame, param) - if err != nil { - return err - } - params = append(params, val) + params = append(params, c.getValue(frame, param)) } if !calleeFn.IsExported() { params = append(params, llvm.Undef(c.i8ptrType)) // context parameter @@ -957,87 +873,49 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { } c.createCall(calleeValue, params, "") - return nil case *ssa.If: - cond, err := c.parseExpr(frame, instr.Cond) - if err != nil { - return err - } + cond := c.getValue(frame, instr.Cond) block := instr.Block() blockThen := frame.blockEntries[block.Succs[0]] blockElse := frame.blockEntries[block.Succs[1]] c.builder.CreateCondBr(cond, blockThen, blockElse) - return nil case *ssa.Jump: blockJump := frame.blockEntries[instr.Block().Succs[0]] c.builder.CreateBr(blockJump) - return nil case *ssa.MapUpdate: - m, err := c.parseExpr(frame, instr.Map) - if err != nil { - return err - } - key, err := c.parseExpr(frame, instr.Key) - if err != nil { - return err - } - value, err := c.parseExpr(frame, instr.Value) - if err != nil { - return err - } + m := c.getValue(frame, instr.Map) + key := c.getValue(frame, instr.Key) + value := c.getValue(frame, instr.Value) mapType := instr.Map.Type().Underlying().(*types.Map) - return c.emitMapUpdate(mapType.Key(), m, key, value, instr.Pos()) + c.emitMapUpdate(mapType.Key(), m, key, value, instr.Pos()) case *ssa.Panic: - value, err := c.parseExpr(frame, instr.X) - if err != nil { - return err - } + value := c.getValue(frame, instr.X) c.createRuntimeCall("_panic", []llvm.Value{value}, "") c.builder.CreateUnreachable() - return nil case *ssa.Return: if len(instr.Results) == 0 { c.builder.CreateRetVoid() - return nil } else if len(instr.Results) == 1 { - val, err := c.parseExpr(frame, instr.Results[0]) - if err != nil { - return err - } - c.builder.CreateRet(val) - return nil + c.builder.CreateRet(c.getValue(frame, instr.Results[0])) } else { // Multiple return values. Put them all in a struct. - retVal, err := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType()) - if err != nil { - return err - } + retVal := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType()) for i, result := range instr.Results { - val, err := c.parseExpr(frame, result) - if err != nil { - return err - } + val := c.getValue(frame, result) retVal = c.builder.CreateInsertValue(retVal, val, i, "") } c.builder.CreateRet(retVal) - return nil } case *ssa.RunDefers: - return c.emitRunDefers(frame) + c.emitRunDefers(frame) case *ssa.Send: - return c.emitChanSend(frame, instr) + c.emitChanSend(frame, instr) case *ssa.Store: - llvmAddr, err := c.parseExpr(frame, instr.Addr) - if err != nil { - return err - } - llvmVal, err := c.parseExpr(frame, instr.Val) - if err != nil { - return err - } + llvmAddr := c.getValue(frame, instr.Addr) + llvmVal := c.getValue(frame, instr.Val) if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 { // nothing to store - return nil + return } store := c.builder.CreateStore(llvmVal, llvmAddr) valType := instr.Addr.Type().Underlying().(*types.Pointer).Elem() @@ -1045,23 +923,16 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { // Volatile store, for memory-mapped registers. store.SetVolatile(true) } - return nil default: - return c.makeError(instr.Pos(), "unknown instruction: "+instr.String()) + c.addError(instr.Pos(), "unknown instruction: "+instr.String()) } } func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, pos token.Pos) (llvm.Value, error) { switch callName { case "append": - src, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } - elems, err := c.parseExpr(frame, args[1]) - if err != nil { - return llvm.Value{}, err - } + src := c.getValue(frame, args[0]) + elems := c.getValue(frame, args[1]) srcBuf := c.builder.CreateExtractValue(src, 0, "append.srcBuf") srcPtr := c.builder.CreateBitCast(srcBuf, c.i8ptrType, "append.srcPtr") srcLen := c.builder.CreateExtractValue(src, 1, "append.srcLen") @@ -1082,10 +953,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, newSlice = c.builder.CreateInsertValue(newSlice, newCap, 2, "") return newSlice, nil case "cap": - value, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, args[0]) var llvmCap llvm.Value switch args[0].Type().(type) { case *types.Chan: @@ -1102,16 +970,11 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, } return llvmCap, nil case "close": - return llvm.Value{}, c.emitChanClose(frame, args[0]) + c.emitChanClose(frame, args[0]) + return llvm.Value{}, nil case "complex": - r, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } - i, err := c.parseExpr(frame, args[1]) - if err != nil { - return llvm.Value{}, err - } + r := c.getValue(frame, args[0]) + i := c.getValue(frame, args[1]) t := args[0].Type().Underlying().(*types.Basic) var cplx llvm.Value switch t.Kind() { @@ -1126,14 +989,8 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, cplx = c.builder.CreateInsertValue(cplx, i, 1, "") return cplx, nil case "copy": - dst, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } - src, err := c.parseExpr(frame, args[1]) - if err != nil { - return llvm.Value{}, err - } + dst := c.getValue(frame, args[0]) + src := c.getValue(frame, args[1]) dstLen := c.builder.CreateExtractValue(dst, 1, "copy.dstLen") srcLen := c.builder.CreateExtractValue(src, 1, "copy.srcLen") dstBuf := c.builder.CreateExtractValue(dst, 0, "copy.dstArray") @@ -1144,26 +1001,14 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, elemSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(elemType), false) return c.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil case "delete": - m, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } - key, err := c.parseExpr(frame, args[1]) - if err != nil { - return llvm.Value{}, err - } + m := c.getValue(frame, args[0]) + key := c.getValue(frame, args[1]) return llvm.Value{}, c.emitMapDelete(args[1].Type(), m, key, pos) case "imag": - cplx, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } + cplx := c.getValue(frame, args[0]) return c.builder.CreateExtractValue(cplx, 1, "imag"), nil case "len": - value, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, args[0]) var llvmLen llvm.Value switch args[0].Type().Underlying().(type) { case *types.Basic, *types.Slice: @@ -1187,10 +1032,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, if i >= 1 && callName == "println" { c.createRuntimeCall("printspace", nil, "") } - value, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, arg) typ := arg.Type().Underlying() switch typ := typ.(type) { case *types.Basic: @@ -1243,29 +1085,22 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string, } return llvm.Value{}, nil // print() or println() returns void case "real": - cplx, err := c.parseExpr(frame, args[0]) - if err != nil { - return llvm.Value{}, err - } + cplx := c.getValue(frame, args[0]) return c.builder.CreateExtractValue(cplx, 0, "real"), nil case "recover": return c.createRuntimeCall("_recover", nil, ""), nil case "ssa:wrapnilchk": // TODO: do an actual nil check? - return c.parseExpr(frame, args[0]) + return c.getValue(frame, args[0]), nil default: return llvm.Value{}, c.makeError(pos, "todo: builtin: "+callName) } } -func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, context llvm.Value, exported bool) (llvm.Value, error) { +func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, context llvm.Value, exported bool) llvm.Value { var params []llvm.Value for _, param := range args { - val, err := c.parseExpr(frame, param) - if err != nil { - return llvm.Value{}, err - } - params = append(params, val) + params = append(params, c.getValue(frame, param)) } if !exported { @@ -1277,15 +1112,12 @@ func (c *Compiler) parseFunctionCall(frame *Frame, args []ssa.Value, llvmFn, con params = append(params, llvm.Undef(c.i8ptrType)) } - return c.createCall(llvmFn, params, ""), nil + return c.createCall(llvmFn, params, "") } func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) { if instr.IsInvoke() { - fnCast, args, err := c.getInvokeCall(frame, instr) - if err != nil { - return llvm.Value{}, err - } + fnCast, args := c.getInvokeCall(frame, instr) return c.createCall(fnCast, args, ""), nil } @@ -1316,15 +1148,12 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e case *ssa.MakeClosure: // A call on a func value, but the callee is trivial to find. For // example: immediately applied functions. - funcValue, err := c.parseExpr(frame, value) - if err != nil { - return llvm.Value{}, err - } + funcValue := c.getValue(frame, value) context = c.extractFuncContext(funcValue) default: panic("StaticCallee returned an unexpected value") } - return c.parseFunctionCall(frame, instr.Args, targetFunc.LLVMFn, context, targetFunc.IsExported()) + return c.parseFunctionCall(frame, instr.Args, targetFunc.LLVMFn, context, targetFunc.IsExported()), nil } // Builtin or function pointer. @@ -1332,10 +1161,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e case *ssa.Builtin: return c.parseBuiltin(frame, instr.Args, call.Name(), instr.Pos()) default: // function pointer - value, err := c.parseExpr(frame, instr.Value) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, instr.Value) // This is a func value, which cannot be called directly. We have to // extract the function pointer and context first from the func value. funcPtr, context, err := c.decodeFuncValue(value, instr.Value.Type().(*types.Signature)) @@ -1343,25 +1169,51 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e return llvm.Value{}, err } c.emitNilCheck(frame, funcPtr, "fpcall") - return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false) + return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false), nil } } -func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { - if value, ok := frame.locals[expr]; ok { - // Value is a local variable that has already been computed. +// getValue returns the LLVM value of a constant, function value, global, or +// already processed SSA expression. +func (c *Compiler) getValue(frame *Frame, expr ssa.Value) llvm.Value { + switch expr := expr.(type) { + case *ssa.Const: + return c.parseConst(frame.fn.LinkName(), expr) + case *ssa.Function: + fn := c.ir.GetFunction(expr) + if fn.IsExported() { + c.addError(expr.Pos(), "cannot use an exported function as value: "+expr.String()) + return llvm.Undef(c.getLLVMType(expr.Type())) + } + return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature) + case *ssa.Global: + value := c.ir.GetGlobal(expr).LLVMGlobal if value.IsNil() { - return llvm.Value{}, c.makeError(expr.Pos(), "undefined local var (from cgo?)") + c.addError(expr.Pos(), "global not found: "+c.ir.GetGlobal(expr).LinkName()) + return llvm.Undef(c.getLLVMType(expr.Type())) } - return value, nil + 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) { 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) @@ -1378,23 +1230,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { } else { buf = c.builder.CreateAlloca(typ, expr.Comment) if c.targetData.TypeAllocSize(typ) != 0 { - zero, err := c.getZeroValue(typ) - if err != nil { - return llvm.Value{}, err - } - c.builder.CreateStore(zero, buf) // zero-initialize var + c.builder.CreateStore(c.getZeroValue(typ), buf) // zero-initialize var } } return buf, nil case *ssa.BinOp: - x, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } - y, err := c.parseExpr(frame, expr.Y) - if err != nil { - return llvm.Value{}, err - } + x := c.getValue(frame, expr.X) + y := c.getValue(frame, expr.Y) return c.parseBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos()) case *ssa.Call: // Passing the current task here to the subroutine. It is only used when @@ -1407,19 +1249,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { // This is different from how the official Go compiler works, because of // heap allocation and because it's easier to implement, see: // https://research.swtch.com/interfaces - return c.parseExpr(frame, expr.X) + return c.getValue(frame, expr.X), nil case *ssa.ChangeType: // This instruction changes the type, but the underlying value remains // the same. This is often a no-op, but sometimes we have to change the // LLVM type as well. - x, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } - llvmType, err := c.getLLVMType(expr.Type()) - if err != nil { - return llvm.Value{}, err - } + x := c.getValue(frame, expr.X) + llvmType := c.getLLVMType(expr.Type()) if x.Type() == llvmType { // Different Go type but same LLVM type (for example, named int). // This is the common case. @@ -1445,33 +1281,21 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String()) } case *ssa.Const: - return c.parseConst(frame.fn.LinkName(), expr) + panic("const is not an expression") case *ssa.Convert: - x, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } + x := c.getValue(frame, expr.X) return c.parseConvert(expr.X.Type(), expr.Type(), x, expr.Pos()) case *ssa.Extract: - value, err := c.parseExpr(frame, expr.Tuple) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, expr.Tuple) result := c.builder.CreateExtractValue(value, expr.Index, "") return result, nil case *ssa.Field: - value, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, expr.X) if s := expr.X.Type().Underlying().(*types.Struct); s.NumFields() > 2 && s.Field(0).Name() == "C union" { // Extract a field from a CGo union. // This could be done directly, but as this is a very infrequent // 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), "") @@ -1480,10 +1304,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { result := c.builder.CreateExtractValue(value, expr.Field, "") return result, nil case *ssa.FieldAddr: - val, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } + val := c.getValue(frame, expr.X) // Check for nil pointer before calculating the address, from the spec: // > For an operand x of type T, the address operation &x generates a // > pointer of type *T to x. [...] If the evaluation of x would cause a @@ -1493,10 +1314,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. @@ -1507,26 +1325,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { return c.builder.CreateGEP(val, indices, ""), nil } case *ssa.Function: - fn := c.ir.GetFunction(expr) - if fn.IsExported() { - return llvm.Value{}, c.makeError(expr.Pos(), "cannot use an exported function as value") - } - return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature) + panic("function is not an expression") case *ssa.Global: - value := c.ir.GetGlobal(expr).LLVMGlobal - if value.IsNil() { - return llvm.Value{}, c.makeError(expr.Pos(), "global not found: "+c.ir.GetGlobal(expr).LinkName()) - } - return value, nil + panic("global is not an expression") case *ssa.Index: - array, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } - index, err := c.parseExpr(frame, expr.Index) - if err != nil { - return llvm.Value{}, err - } + array := c.getValue(frame, expr.X) + index := c.getValue(frame, expr.Index) // Check bounds. arrayLen := expr.X.Type().(*types.Array).Len() @@ -1541,14 +1345,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { ptr := c.builder.CreateGEP(alloca, []llvm.Value{zero, index}, "index.gep") return c.builder.CreateLoad(ptr, "index.load"), nil case *ssa.IndexAddr: - val, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } - index, err := c.parseExpr(frame, expr.Index) - if err != nil { - return llvm.Value{}, err - } + val := c.getValue(frame, expr.X) + index := c.getValue(frame, expr.Index) // Get buffer pointer and length var bufptr, buflen llvm.Value @@ -1592,14 +1390,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { panic("unreachable") } case *ssa.Lookup: - value, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, nil - } - index, err := c.parseExpr(frame, expr.Index) - if err != nil { - return llvm.Value{}, nil - } + value := c.getValue(frame, expr.X) + index := c.getValue(frame, expr.Index) switch xType := expr.X.Type().Underlying().(type) { case *types.Basic: // Value type must be a string, which is a basic type. @@ -1629,21 +1421,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { case *ssa.MakeClosure: return c.parseMakeClosure(frame, expr) case *ssa.MakeInterface: - val, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } + val := c.getValue(frame, expr.X) return c.parseMakeInterface(val, expr.X.Type(), expr.Pos()) case *ssa.MakeMap: mapType := expr.Type().Underlying().(*types.Map) - 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) @@ -1651,19 +1434,10 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { hashmap := c.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize}, "") return hashmap, nil case *ssa.MakeSlice: - sliceLen, err := c.parseExpr(frame, expr.Len) - if err != nil { - return llvm.Value{}, nil - } - sliceCap, err := c.parseExpr(frame, expr.Cap) - if err != nil { - return llvm.Value{}, nil - } + sliceLen := c.getValue(frame, expr.Len) + sliceCap := c.getValue(frame, expr.Cap) sliceType := expr.Type().Underlying().(*types.Slice) - llvmElemType, 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) @@ -1712,25 +1486,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { return slice, nil case *ssa.Next: rangeVal := expr.Iter.(*ssa.Range).X - llvmRangeVal, err := c.parseExpr(frame, rangeVal) - if err != nil { - return llvm.Value{}, err - } - it, err := c.parseExpr(frame, expr.Iter) - if err != nil { - return llvm.Value{}, err - } + llvmRangeVal := c.getValue(frame, rangeVal) + it := c.getValue(frame, expr.Iter) if expr.IsString { return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil } else { // map - 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") @@ -1745,11 +1507,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: @@ -1763,19 +1521,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { panic("unknown type in range: " + typ.String()) } it := c.builder.CreateAlloca(iteratorType, "range.it") - zero, err := c.getZeroValue(iteratorType) - if err != nil { - return llvm.Value{}, nil - } - c.builder.CreateStore(zero, it) + c.builder.CreateStore(c.getZeroValue(iteratorType), it) return it, nil 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 {} @@ -1796,20 +1547,14 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { if expr.Max != nil { return llvm.Value{}, c.makeError(expr.Pos(), "todo: full slice expressions (with max): "+expr.Type().String()) } - value, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } + value := c.getValue(frame, expr.X) var lowType, highType *types.Basic var low, high llvm.Value if expr.Low != nil { lowType = expr.Low.Type().Underlying().(*types.Basic) - low, err = c.parseExpr(frame, expr.Low) - if err != nil { - return llvm.Value{}, nil - } + low = c.getValue(frame, expr.Low) if low.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if lowType.Info()&types.IsUnsigned != 0 { low = c.builder.CreateZExt(low, c.uintptrType, "") @@ -1824,10 +1569,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { if expr.High != nil { highType = expr.High.Type().Underlying().(*types.Basic) - high, err = c.parseExpr(frame, expr.High) - if err != nil { - return llvm.Value{}, nil - } + high = c.getValue(frame, expr.High) if high.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if highType.Info()&types.IsUnsigned != 0 { high = c.builder.CreateZExt(high, c.uintptrType, "") @@ -1934,10 +1676,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "") newLen := c.builder.CreateSub(high, low, "") - str, err := c.getZeroValue(c.mod.GetTypeByName("runtime._string")) - if err != nil { - return llvm.Value{}, err - } + str := llvm.Undef(c.mod.GetTypeByName("runtime._string")) str = c.builder.CreateInsertValue(str, newPtr, 0, "") str = c.builder.CreateInsertValue(str, newLen, 1, "") return str, nil @@ -1946,7 +1685,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { return llvm.Value{}, c.makeError(expr.Pos(), "unknown slice type: "+typ.String()) } case *ssa.TypeAssert: - return c.parseTypeAssert(frame, expr) + return c.parseTypeAssert(frame, expr), nil case *ssa.UnOp: return c.parseUnOp(frame, expr) default: @@ -2245,20 +1984,17 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value, p } } -func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error) { +func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value { switch typ := expr.Type().Underlying().(type) { case *types.Basic: - llvmType, 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) if b { n = 1 } - return llvm.ConstInt(llvmType, n, false), nil + return llvm.ConstInt(llvmType, n, false) } else if typ.Info()&types.IsString != 0 { str := constant.StringVal(expr.Value) strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false) @@ -2271,94 +2007,69 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) strPtr := c.builder.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "") strObj := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._string"), []llvm.Value{strPtr, strLen}) - return strObj, nil + return strObj } else if typ.Kind() == types.UnsafePointer { if !expr.IsNil() { value, _ := constant.Uint64Val(expr.Value) - return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.i8ptrType), nil + return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.i8ptrType) } - return llvm.ConstNull(c.i8ptrType), nil + return llvm.ConstNull(c.i8ptrType) } else if typ.Info()&types.IsUnsigned != 0 { n, _ := constant.Uint64Val(expr.Value) - return llvm.ConstInt(llvmType, n, false), nil + return llvm.ConstInt(llvmType, n, false) } else if typ.Info()&types.IsInteger != 0 { // signed n, _ := constant.Int64Val(expr.Value) - return llvm.ConstInt(llvmType, uint64(n), true), nil + return llvm.ConstInt(llvmType, uint64(n), true) } else if typ.Info()&types.IsFloat != 0 { n, _ := constant.Float64Val(expr.Value) - return llvm.ConstFloat(llvmType, n), nil + return llvm.ConstFloat(llvmType, n) } else if typ.Kind() == types.Complex64 { - r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32])) - if err != nil { - return llvm.Value{}, err - } - i, err := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32])) - if err != nil { - return llvm.Value{}, err - } + r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32])) + i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32])) cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)) cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = c.builder.CreateInsertValue(cplx, i, 1, "") - return cplx, nil + return cplx } else if typ.Kind() == types.Complex128 { - r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64])) - if err != nil { - return llvm.Value{}, err - } - i, err := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64])) - if err != nil { - return llvm.Value{}, err - } + r := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64])) + i := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64])) cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)) cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = c.builder.CreateInsertValue(cplx, i, 1, "") - return cplx, nil + return cplx } else { - return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String()) + panic("unknown constant of basic type: " + expr.String()) } case *types.Chan: - sig, err := c.getLLVMType(expr.Type()) - if err != nil { - return llvm.Value{}, err + if expr.Value != nil { + panic("expected nil chan constant") } - return c.getZeroValue(sig) + return c.getZeroValue(c.getLLVMType(expr.Type())) case *types.Signature: if expr.Value != nil { - return llvm.Value{}, errors.New("non-nil signature constant") + panic("expected nil signature constant") } - sig, err := c.getLLVMType(expr.Type()) - if err != nil { - return llvm.Value{}, err - } - return c.getZeroValue(sig) + return c.getZeroValue(c.getLLVMType(expr.Type())) case *types.Interface: if expr.Value != nil { - return llvm.Value{}, errors.New("non-nil interface constant") + panic("expected nil interface constant") } // Create a generic nil interface with no dynamic type (typecode=0). fields := []llvm.Value{ llvm.ConstInt(c.uintptrType, 0, false), llvm.ConstPointerNull(c.i8ptrType), } - itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields) - return itf, nil + return llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields) case *types.Pointer: if expr.Value != nil { - return llvm.Value{}, errors.New("non-nil pointer constant") + panic("expected nil pointer constant") } - llvmType, err := c.getLLVMType(typ) - if err != nil { - return llvm.Value{}, err - } - return llvm.ConstPointerNull(llvmType), nil + return llvm.ConstPointerNull(c.getLLVMType(typ)) 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 + panic("expected nil slice constant") } + 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{ @@ -2366,28 +2077,22 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error llvmLen, // len llvmLen, // cap }, false) - return slice, nil + return slice case *types.Map: if !expr.IsNil() { // I believe this is not allowed by the Go spec. panic("non-nil map constant") } - llvmType, err := c.getLLVMType(typ) - if err != nil { - return llvm.Value{}, err - } + llvmType := c.getLLVMType(typ) return c.getZeroValue(llvmType) default: - return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String()) + panic("unknown constant: " + expr.String()) } } 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()) @@ -2543,10 +2248,7 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p } func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { - x, err := c.parseExpr(frame, unop.X) - if err != nil { - return llvm.Value{}, err - } + x := c.getValue(frame, unop.X) switch unop.Op { case token.NOT: // !x return c.builder.CreateNot(x, ""), nil @@ -2566,7 +2268,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { valType := unop.X.Type().Underlying().(*types.Pointer).Elem() if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 { // zero-length data - return c.getZeroValue(x.Type().ElementType()) + return c.getZeroValue(x.Type().ElementType()), nil } else if strings.HasSuffix(unop.X.String(), "$funcaddr") { // CGo function pointer. The cgo part has rewritten CGo function // pointers as stub global variables of the form: @@ -2592,7 +2294,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { case token.XOR: // ^x, toggle all bits in integer return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil case token.ARROW: // <-x, receive from channel - return c.emitChanRecv(frame, unop) + return c.emitChanRecv(frame, unop), nil default: return llvm.Value{}, c.makeError(unop.Pos(), "todo: unknown unop") } diff --git a/compiler/defer.go b/compiler/defer.go index f11c27ef0b..016c1c73f0 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -36,7 +36,7 @@ func (c *Compiler) deferInitFunc(frame *Frame) { // emitDefer emits a single defer instruction, to be run when this function // returns. -func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { +func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) { // The pointer to the previous defer struct, which we will replace to // make a linked list. next := c.builder.CreateLoad(frame.deferPtr, "defer.next") @@ -56,18 +56,12 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // Collect all values to be put in the struct (starting with // runtime._defer fields, followed by the call parameters). - itf, err := c.parseExpr(frame, instr.Call.Value) // interface - if err != nil { - return err - } + itf := c.getValue(frame, instr.Call.Value) // interface receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver") values = []llvm.Value{callback, next, receiverValue} valueTypes = append(valueTypes, c.i8ptrType) for _, arg := range instr.Call.Args { - val, err := c.parseExpr(frame, arg) - if err != nil { - return err - } + val := c.getValue(frame, arg) values = append(values, val) valueTypes = append(valueTypes, val.Type()) } @@ -86,10 +80,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // runtime._defer fields). values = []llvm.Value{callback, next} for _, param := range instr.Call.Args { - llvmParam, err := c.parseExpr(frame, param) - if err != nil { - return err - } + llvmParam := c.getValue(frame, param) values = append(values, llvmParam) valueTypes = append(valueTypes, llvmParam.Type()) } @@ -101,10 +92,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // pointer. // TODO: ignore this closure entirely and put pointers to the free // variables directly in the defer struct, avoiding a memory allocation. - closure, err := c.parseExpr(frame, instr.Call.Value) - if err != nil { - return err - } + closure := c.getValue(frame, instr.Call.Value) context := c.builder.CreateExtractValue(closure, 0, "") // Get the callback number. @@ -120,10 +108,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // context pointer). values = []llvm.Value{callback, next} for _, param := range instr.Call.Args { - llvmParam, err := c.parseExpr(frame, param) - if err != nil { - return err - } + llvmParam := c.getValue(frame, param) values = append(values, llvmParam) valueTypes = append(valueTypes, llvmParam.Type()) } @@ -131,15 +116,13 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { valueTypes = append(valueTypes, context.Type()) } else { - return c.makeError(instr.Pos(), "todo: defer on uncommon function call type") + c.addError(instr.Pos(), "todo: defer on uncommon function call type") + return } // Make a struct out of the collected values to put in the defer frame. deferFrameType := c.ctx.StructType(valueTypes, false) - deferFrame, err := c.getZeroValue(deferFrameType) - if err != nil { - return err - } + deferFrame := c.getZeroValue(deferFrameType) for i, value := range values { deferFrame = c.builder.CreateInsertValue(deferFrame, value, i, "") } @@ -151,11 +134,10 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // Push it on top of the linked list by replacing deferPtr. allocaCast := c.builder.CreateBitCast(alloca, next.Type(), "defer.alloca.cast") c.builder.CreateStore(allocaCast, frame.deferPtr) - return nil } // emitRunDefers emits code to run all deferred functions. -func (c *Compiler) emitRunDefers(frame *Frame) error { +func (c *Compiler) emitRunDefers(frame *Frame) { // Add a loop like the following: // for stack != nil { // _stack := stack @@ -220,11 +202,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") @@ -246,10 +224,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error { // Parent coroutine handle. forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) - fnPtr, _, err := c.getInvokeCall(frame, callback) - if err != nil { - return err - } + fnPtr, _ := c.getInvokeCall(frame, callback) c.createCall(fnPtr, forwardParams, "") case *ir.Function: @@ -258,11 +233,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") @@ -292,11 +263,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) @@ -334,5 +301,4 @@ func (c *Compiler) emitRunDefers(frame *Frame) error { // End of loop. c.builder.SetInsertPointAtEnd(end) - return nil } diff --git a/compiler/errors.go b/compiler/errors.go index 1d76b4231b..e003046435 100644 --- a/compiler/errors.go +++ b/compiler/errors.go @@ -12,3 +12,7 @@ func (c *Compiler) makeError(pos token.Pos, msg string) types.Error { Msg: msg, } } + +func (c *Compiler) addError(pos token.Pos, msg string) { + c.diagnostics = append(c.diagnostics, c.makeError(pos, msg)) +} diff --git a/compiler/func.go b/compiler/func.go index 29ceb6131b..3bee9112b9 100644 --- a/compiler/func.go +++ b/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 @@ -213,10 +190,7 @@ func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.V boundVarTypes := make([]llvm.Type, 0, len(expr.Bindings)) for _, binding := range expr.Bindings { // The context stores the bound variables. - llvmBoundVar, err := c.parseExpr(frame, binding) - if err != nil { - return llvm.Value{}, err - } + llvmBoundVar := c.getValue(frame, binding) boundVars = append(boundVars, llvmBoundVar) boundVarTypes = append(boundVarTypes, llvmBoundVar.Type()) } @@ -261,5 +235,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 } diff --git a/compiler/inlineasm.go b/compiler/inlineasm.go index ee33bd0797..b832e43a16 100644 --- a/compiler/inlineasm.go +++ b/compiler/inlineasm.go @@ -68,11 +68,7 @@ func (c *Compiler) emitAsmFull(frame *Frame, instr *ssa.CallCommon) (llvm.Value, } key := constant.StringVal(r.Key.(*ssa.Const).Value) //println("value:", r.Value.(*ssa.MakeInterface).X.String()) - value, err := c.parseExpr(frame, r.Value.(*ssa.MakeInterface).X) - if err != nil { - return llvm.Value{}, err - } - registers[key] = value + registers[key] = c.getValue(frame, r.Value.(*ssa.MakeInterface).X) case *ssa.Call: if r.Common() == instr { break @@ -145,10 +141,7 @@ func (c *Compiler) emitSVCall(frame *Frame, args []ssa.Value) (llvm.Value, error } else { constraints += ",{r" + strconv.Itoa(i) + "}" } - llvmValue, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, err - } + llvmValue := c.getValue(frame, arg) llvmArgs = append(llvmArgs, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } diff --git a/compiler/interface.go b/compiler/interface.go index 46ebee0a5c..c9624f1674 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -274,19 +274,9 @@ func (c *Compiler) getMethodSignature(method *types.Func) llvm.Value { // // Type asserts on concrete types are trivial: just compare type numbers. Type // asserts on interfaces are more difficult, see the comments in the function. -func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Value, error) { - itf, err := c.parseExpr(frame, expr.X) - if err != nil { - return llvm.Value{}, err - } - assertedType, err := c.getLLVMType(expr.AssertedType) - if err != nil { - return llvm.Value{}, err - } - valueNil, err := c.getZeroValue(assertedType) - if err != nil { - return llvm.Value{}, err - } +func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) llvm.Value { + itf := c.getValue(frame, expr.X) + assertedType := c.getLLVMType(expr.AssertedType) actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type") commaOk := llvm.Value{} @@ -345,10 +335,7 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "") valueOk = c.builder.CreateLoad(valuePtrCast, "typeassert.value.ok") } else if size == 0 { - valueOk, err = c.getZeroValue(assertedType) - if err != nil { - return llvm.Value{}, err - } + valueOk = c.getZeroValue(assertedType) } else { // Value was stored directly in the interface. switch assertedType.TypeKind() { @@ -372,34 +359,28 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val // Continue after the if statement. c.builder.SetInsertPointAtEnd(nextBlock) phi := c.builder.CreatePHI(assertedType, "typeassert.value") - phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock}) + phi.AddIncoming([]llvm.Value{c.getZeroValue(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock}) if expr.CommaOk { tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean - return tuple, nil + return tuple } else { // This is kind of dirty as the branch above becomes mostly useless, // but hopefully this gets optimized away. c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "") - return phi, nil + return phi } } // getInvokeCall creates and returns the function pointer and parameters of an // interface call. It can be used in a call or defer instruction. -func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value, error) { +func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value) { // Call an interface method with dynamic dispatch. - itf, err := c.parseExpr(frame, instr.Value) // interface - if err != nil { - return llvm.Value{}, nil, err - } + itf := c.getValue(frame, instr.Value) // interface - llvmFnType, 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{ @@ -413,11 +394,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu args := []llvm.Value{receiverValue} for _, arg := range instr.Args { - val, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, nil, err - } - args = append(args, val) + args = append(args, c.getValue(frame, arg)) } // Add the context parameter. An interface call never takes a context but we // have to supply the parameter anyway. @@ -425,7 +402,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu // Add the parent goroutine handle. args = append(args, llvm.Undef(c.i8ptrType)) - return fnCast, args, nil + return fnCast, args } // interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and @@ -450,10 +427,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? @@ -480,7 +454,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 @@ -490,10 +464,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{}) } @@ -531,6 +502,4 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er ret := c.builder.CreateCall(fn.LLVMFn, params, "ret") c.builder.CreateRet(ret) } - - return nil } diff --git a/compiler/map.go b/compiler/map.go index dc5ddead9d..e69393c22e 100644 --- a/compiler/map.go +++ b/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 @@ -42,7 +39,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu } } -func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) error { +func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) { valueAlloca := c.builder.CreateAlloca(value.Type(), "hashmap.value") c.builder.CreateStore(value, valueAlloca) valuePtr := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "hashmap.valueptr") @@ -51,7 +48,6 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p // key is a string params := []llvm.Value{m, key, valuePtr} c.createRuntimeCall("hashmapStringSet", params, "") - return nil } else if hashmapIsBinaryKey(keyType) { // key can be compared with runtime.memequal keyAlloca := c.builder.CreateAlloca(key.Type(), "hashmap.key") @@ -59,9 +55,8 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p keyPtr := c.builder.CreateBitCast(keyAlloca, c.i8ptrType, "hashmap.keyptr") params := []llvm.Value{m, keyPtr, valuePtr} c.createRuntimeCall("hashmapBinarySet", params, "") - return nil } else { - return c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String()) + c.addError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String()) } } diff --git a/compiler/optimizer.go b/compiler/optimizer.go index dfa005da69..9b6ccae71f 100644 --- a/compiler/optimizer.go +++ b/compiler/optimizer.go @@ -249,7 +249,7 @@ func (c *Compiler) OptimizeAllocs() { sizeInWords := (size + uint64(alignment) - 1) / uint64(alignment) allocaType := llvm.ArrayType(c.ctx.IntType(alignment*8), int(sizeInWords)) alloca := c.builder.CreateAlloca(allocaType, "stackalloc.alloca") - zero, _ := c.getZeroValue(alloca.Type().ElementType()) + zero := c.getZeroValue(alloca.Type().ElementType()) c.builder.CreateStore(zero, alloca) stackalloc := c.builder.CreateBitCast(alloca, bitcast.Type(), "stackalloc") bitcast.ReplaceAllUsesWith(stackalloc) diff --git a/compiler/syscall.go b/compiler/syscall.go index f9e3e4657c..d14e897223 100644 --- a/compiler/syscall.go +++ b/compiler/syscall.go @@ -51,10 +51,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value, "{r12}", "{r13}", }[i] - llvmValue, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, err - } + llvmValue := c.getValue(frame, arg) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } @@ -80,10 +77,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value, "{r5}", "{r6}", }[i] - llvmValue, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, err - } + llvmValue := c.getValue(frame, arg) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } @@ -113,10 +107,7 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value, "{x4}", "{x5}", }[i] - llvmValue, err := c.parseExpr(frame, arg) - if err != nil { - return llvm.Value{}, err - } + llvmValue := c.getValue(frame, arg) args = append(args, llvmValue) argTypes = append(argTypes, llvmValue.Type()) } diff --git a/main.go b/main.go index 28cf34f362..9f2c61e35b 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,16 @@ func (e *commandError) Error() string { return e.Msg + " " + e.File + ": " + e.Err.Error() } +// multiError is a list of multiple errors (actually: diagnostics) returned +// during LLVM IR generation. +type multiError struct { + Errs []error +} + +func (e *multiError) Error() string { + return e.Errs[0].Error() +} + type BuildConfig struct { opt string gc string @@ -75,9 +85,9 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act } // Compile Go code to IR. - err = c.Compile(pkgName) - if err != nil { - return err + errs := c.Compile(pkgName) + if errs != nil { + return &multiError{errs} } if config.printIR { fmt.Println("Generated LLVM IR:") @@ -496,6 +506,10 @@ func handleCompilerError(err error) { for _, err := range errLoader.Errs { fmt.Fprintln(os.Stderr, err) } + } else if errMulti, ok := err.(*multiError); ok { + for _, err := range errMulti.Errs { + fmt.Fprintln(os.Stderr, err) + } } else { fmt.Fprintln(os.Stderr, "error:", err) }