diff options
author | Ayke van Laethem <[email protected]> | 2019-04-21 14:04:22 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2019-04-26 08:52:10 +0200 |
commit | 6d2380921818fdbbdbca0db6c1ef732654792d58 (patch) | |
tree | af9b070151311e881862842a60a2d7dbf41e6993 /compiler | |
parent | 024eceb476b1c0d4f129bfd7617830ca49ae963b (diff) | |
download | tinygo-6d2380921818fdbbdbca0db6c1ef732654792d58.tar.gz tinygo-6d2380921818fdbbdbca0db6c1ef732654792d58.zip |
compiler: simplify code around getZeroValue
The LLVM library we use does not (yet) provide a llvm.Zero (like it
provides a llvm.Undef) so we have implemented our own. However, in
theory it might return an error in some cases.
No real-world errors have been seen in a while and errors would likely
indicate a serious compiler bug anyway (not an external error), so make
it panic instead of returning an error.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/calls.go | 5 | ||||
-rw-r--r-- | compiler/compiler.go | 63 | ||||
-rw-r--r-- | compiler/defer.go | 5 | ||||
-rw-r--r-- | compiler/interface.go | 11 | ||||
-rw-r--r-- | compiler/optimizer.go | 2 |
5 files changed, 24 insertions, 62 deletions
diff --git a/compiler/calls.go b/compiler/calls.go index 2ac293ba1..b5296f91a 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/compiler.go b/compiler/compiler.go index 28b9f29bd..094568c5a 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -297,11 +297,7 @@ 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)) } } @@ -544,42 +540,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()) } } @@ -1010,10 +999,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { return nil } 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 { @@ -1380,11 +1366,7 @@ 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 @@ -1765,11 +1747,7 @@ 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 { @@ -1936,10 +1914,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 @@ -2323,7 +2298,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error if err != nil { return llvm.Value{}, err } - return c.getZeroValue(sig) + return c.getZeroValue(sig), nil case *types.Signature: if expr.Value != nil { return llvm.Value{}, errors.New("non-nil signature constant") @@ -2332,7 +2307,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error if err != nil { return llvm.Value{}, err } - return c.getZeroValue(sig) + return c.getZeroValue(sig), nil case *types.Interface: if expr.Value != nil { return llvm.Value{}, errors.New("non-nil interface constant") @@ -2378,7 +2353,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error if err != nil { return llvm.Value{}, err } - return c.getZeroValue(llvmType) + return c.getZeroValue(llvmType), nil default: return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String()) } @@ -2568,7 +2543,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: diff --git a/compiler/defer.go b/compiler/defer.go index f11c27ef0..0bdd5d09f 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -136,10 +136,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) error { // 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, "") } diff --git a/compiler/interface.go b/compiler/interface.go index 46ebee0a5..94299a918 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -283,10 +283,6 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val if err != nil { return llvm.Value{}, err } - valueNil, err := c.getZeroValue(assertedType) - if err != nil { - return llvm.Value{}, err - } actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type") commaOk := llvm.Value{} @@ -345,10 +341,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,7 +365,7 @@ 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 diff --git a/compiler/optimizer.go b/compiler/optimizer.go index d922b0a43..d412b97b8 100644 --- a/compiler/optimizer.go +++ b/compiler/optimizer.go @@ -272,7 +272,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) |