aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2019-04-21 14:04:22 +0200
committerRon Evans <[email protected]>2019-04-26 08:52:10 +0200
commit6d2380921818fdbbdbca0db6c1ef732654792d58 (patch)
treeaf9b070151311e881862842a60a2d7dbf41e6993
parent024eceb476b1c0d4f129bfd7617830ca49ae963b (diff)
downloadtinygo-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.
-rw-r--r--compiler/calls.go5
-rw-r--r--compiler/compiler.go63
-rw-r--r--compiler/defer.go5
-rw-r--r--compiler/interface.go11
-rw-r--r--compiler/optimizer.go2
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)