From bd05239c918ff5e18e96cf05e855332257fffac5 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 19 Mar 2020 20:47:31 +0100 Subject: [PATCH] compiler: do not perform nil checking when indexing slices The x/tools/go/ssa package splits slice loads/stores into two operations. So for code like this: x = p[3] It has two instructions: x_ptr = &p[3] x = *x_ptr This makes the IR simpler, but also means we're accidentally inserting more nil checks than necessary: the slice index operation has effectively already checked for nil by performing a bounds check. Therefore, omit nil pointer checks for pointers created by *ssa.IndexAddr. This change is necessary to make sure a future removal of runtime.isnil will not cause the escape analysis pass to regress. Apart from that, it reduces code size slightly in many smoke tests (with no increases in code size). --- compiler/compiler.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index 0e459be375..ce1ab9e400 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1146,7 +1146,9 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) { case *ssa.Store: llvmAddr := c.getValue(frame, instr.Addr) llvmVal := c.getValue(frame, instr.Val) - c.emitNilCheck(frame, llvmAddr, "store") + if _, ok := instr.Addr.(*ssa.IndexAddr); !ok { + c.emitNilCheck(frame, llvmAddr, "store") + } if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 { // nothing to store return @@ -2563,7 +2565,9 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { } return c.builder.CreateBitCast(fn, c.i8ptrType, ""), nil } else { - c.emitNilCheck(frame, x, "deref") + if _, ok := unop.X.(*ssa.IndexAddr); !ok { + c.emitNilCheck(frame, x, "deref") + } load := c.builder.CreateLoad(x, "") return load, nil }