From 26acc89f9cf8fc1df019f28a2ab41d428a3b32ff Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 9 Nov 2018 15:48:47 +0100 Subject: [PATCH] compiler: avoid load/store on zero-length data These loads/stores probably would get optimized away anyway, but not emitting them helps the init interpreter. --- compiler/compiler.go | 31 ++++++++++++++++++++++--------- compiler/interface.go | 10 +++++++++- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index 656d29e2..c6279851 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -499,6 +499,8 @@ func (c *Compiler) Compile(mainPath string) error { } c.builder.CreateRetVoid() + // Add a wrapper for the main.main function, either calling it directly or + // setting up the scheduler with it. mainWrapper := c.ir.GetFunction(c.ir.Program.ImportedPackage("runtime").Members["mainWrapper"].(*ssa.Function)) mainWrapper.LLVMFn.SetLinkage(llvm.InternalLinkage) mainWrapper.LLVMFn.SetUnnamedAddr(true) @@ -1650,6 +1652,10 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { if err != nil { return err } + if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 { + // nothing to store + return nil + } store := c.builder.CreateStore(llvmVal, llvmAddr) valType := instr.Addr.Type().(*types.Pointer).Elem() if c.ir.IsVolatile(valType) { @@ -2141,11 +2147,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "") } else { buf = c.builder.CreateAlloca(typ, expr.Comment) - zero, err := c.getZeroValue(typ) - if err != nil { - return llvm.Value{}, err + 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(zero, buf) // zero-initialize var } return buf, nil case *ssa.BinOp: @@ -3215,12 +3223,17 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { } case token.MUL: // *x, dereference pointer valType := unop.X.Type().(*types.Pointer).Elem() - load := c.builder.CreateLoad(x, "") - if c.ir.IsVolatile(valType) { - // Volatile load, for memory-mapped registers. - load.SetVolatile(true) + if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 { + // zero-length data + return c.getZeroValue(x.Type().ElementType()) + } else { + load := c.builder.CreateLoad(x, "") + if c.ir.IsVolatile(valType) { + // Volatile load, for memory-mapped registers. + load.SetVolatile(true) + } + return load, nil } - return load, nil case token.XOR: // ^x, toggle all bits in integer return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil default: diff --git a/compiler/interface.go b/compiler/interface.go index 36603e05..129ceb1b 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -37,6 +37,8 @@ func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, global str c.builder.CreateStore(val, itfValueCast) itfValue = c.builder.CreateBitCast(itfValueCast, c.i8ptrType, "") } + } else if size == 0 { + itfValue = llvm.ConstPointerNull(c.i8ptrType) } else { // Directly place the value in the interface. switch val.Type().TypeKind() { @@ -152,10 +154,16 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val // Type assert on concrete type. Extract the underlying type from // the interface (but only after checking it matches). valuePtr := c.builder.CreateExtractValue(itf, 1, "typeassert.value.ptr") - if c.targetData.TypeAllocSize(assertedType) > c.targetData.TypeAllocSize(c.i8ptrType) { + size := c.targetData.TypeAllocSize(assertedType) + if size > c.targetData.TypeAllocSize(c.i8ptrType) { // Value was stored in an allocated buffer, load it from there. 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 + } } else { // Value was stored directly in the interface. switch assertedType.TypeKind() {