Skip to content

Commit f8876ea

Browse files
aykevldeadprogram
authored andcommitted
compiler, transform: remove runtime.isnil hack
This hack was originally introduced in #251 to fix an escape analysis regression after #222 introduced nil checks. Since a new optimization in LLVM (see https://reviews.llvm.org/D60047) this hack is not necessary anymore and can be removed. I've compared all regular tests and smoke tests before and after to check the size. In most cases this change was an improvement although there are a few regressions.
1 parent bbfa601 commit f8876ea

File tree

7 files changed

+13
-72
lines changed

7 files changed

+13
-72
lines changed

compiler/asserts.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -176,23 +176,11 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
176176
}
177177

178178
// Compare against nil.
179-
var isnil llvm.Value
180-
if ptr.Type().PointerAddressSpace() == 0 {
181-
// Do the nil check using the isnil builtin, which marks the parameter
182-
// as nocapture.
183-
// The reason it has to go through a builtin, is that a regular icmp
184-
// instruction may capture the pointer in LLVM semantics, see
185-
// https://reviews.llvm.org/D60047 for details. Pointer capturing
186-
// unfortunately breaks escape analysis, so we use this trick to let the
187-
// functionattr pass know that this pointer doesn't really escape.
188-
ptr = b.CreateBitCast(ptr, b.i8ptrType, "")
189-
isnil = b.createRuntimeCall("isnil", []llvm.Value{ptr}, "")
190-
} else {
191-
// Do the nil check using a regular icmp. This can happen with function
192-
// pointers on AVR, which don't benefit from escape analysis anyway.
193-
nilptr := llvm.ConstPointerNull(ptr.Type())
194-
isnil = b.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
195-
}
179+
// We previously used a hack to make sure this wouldn't break escape
180+
// analysis, but this is not necessary anymore since
181+
// https://reviews.llvm.org/D60047 has been merged.
182+
nilptr := llvm.ConstPointerNull(ptr.Type())
183+
isnil := b.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
196184

197185
// Emit the nil check in IR.
198186
b.createRuntimeAssert(isnil, blockPrefix, "nilPanic")

compiler/compiler.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,6 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
339339
c.mod.NamedFunction("runtime.alloc").AddAttributeAtIndex(0, getAttr(attrName))
340340
}
341341

342-
// See createNilCheck in asserts.go.
343-
c.mod.NamedFunction("runtime.isnil").AddAttributeAtIndex(1, nocapture)
344-
345342
// On *nix systems, the "abort" functuion in libc is used to handle fatal panics.
346343
// Mark it as noreturn so LLVM can optimize away code.
347344
if abort := c.mod.NamedFunction("abort"); !abort.IsNil() && abort.IsDeclaration() {

src/runtime/panic.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ func _recover() interface{} {
2727
return nil
2828
}
2929

30-
// See emitNilCheck in compiler/asserts.go.
31-
// This function is a dummy function that has its first and only parameter
32-
// marked 'nocapture' to work around a limitation in LLVM: a regular pointer
33-
// comparison captures the pointer.
34-
func isnil(ptr *uint8) bool {
35-
return ptr == nil
36-
}
37-
3830
// Panic when trying to dereference a nil pointer.
3931
func nilPanic() {
4032
runtimePanic("nil pointer dereference")

transform/func-lowering.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,8 @@ func LowerFuncValues(mod llvm.Module) {
197197
panic("expected inttoptr")
198198
}
199199
for _, ptrUse := range getUses(callIntPtr) {
200-
if !ptrUse.IsABitCastInst().IsNil() {
201-
for _, bitcastUse := range getUses(ptrUse) {
202-
if bitcastUse.IsACallInst().IsNil() || bitcastUse.CalledValue().IsAFunction().IsNil() {
203-
panic("expected a call instruction")
204-
}
205-
switch bitcastUse.CalledValue().Name() {
206-
case "runtime.isnil":
207-
bitcastUse.ReplaceAllUsesWith(llvm.ConstInt(ctx.Int1Type(), 0, false))
208-
bitcastUse.EraseFromParentAsInstruction()
209-
default:
210-
panic("expected a call to runtime.isnil")
211-
}
212-
}
200+
if !ptrUse.IsAICmpInst().IsNil() {
201+
ptrUse.ReplaceAllUsesWith(llvm.ConstInt(ctx.Int1Type(), 0, false))
213202
} else if !ptrUse.IsACallInst().IsNil() && ptrUse.CalledValue() == callIntPtr {
214203
addFuncLoweringSwitch(mod, builder, funcID, ptrUse, func(funcPtr llvm.Value, params []llvm.Value) llvm.Value {
215204
return builder.CreateCall(funcPtr, params, "")

transform/optimizer.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,24 +98,6 @@ func Optimize(mod llvm.Module, config *compileopts.Config, optLevel, sizeLevel i
9898
OptimizeAllocs(mod)
9999
OptimizeStringToBytes(mod)
100100

101-
// Lower runtime.isnil calls to regular nil comparisons.
102-
isnil := mod.NamedFunction("runtime.isnil")
103-
if !isnil.IsNil() {
104-
builder := mod.Context().NewBuilder()
105-
defer builder.Dispose()
106-
for _, use := range getUses(isnil) {
107-
builder.SetInsertPointBefore(use)
108-
ptr := use.Operand(0)
109-
if !ptr.IsABitCastInst().IsNil() {
110-
ptr = ptr.Operand(0)
111-
}
112-
nilptr := llvm.ConstPointerNull(ptr.Type())
113-
icmp := builder.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
114-
use.ReplaceAllUsesWith(icmp)
115-
use.EraseFromParentAsInstruction()
116-
}
117-
}
118-
119101
} else {
120102
// Must be run at any optimization level.
121103
err := LowerInterfaces(mod)

transform/testdata/func-lowering.ll

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ declare void @"internal/task.start"(i32, i8*, i8*, i8*)
1919

2020
declare void @runtime.nilPanic(i8*, i8*)
2121

22-
declare i1 @runtime.isnil(i8*, i8*, i8*)
23-
2422
declare void @"main$1"(i32, i8*, i8*)
2523

2624
declare void @"main$2"(i32, i8*, i8*)
@@ -38,9 +36,8 @@ define void @runFunc1(i8*, i32, i8, i8* %context, i8* %parentHandle) {
3836
entry:
3937
%3 = call i32 @runtime.getFuncPtr(i8* %0, i32 %1, %runtime.typecodeID* @"reflect/types.type:func:{basic:int8}{}", i8* undef, i8* null)
4038
%4 = inttoptr i32 %3 to void (i8, i8*, i8*)*
41-
%5 = bitcast void (i8, i8*, i8*)* %4 to i8*
42-
%6 = call i1 @runtime.isnil(i8* %5, i8* undef, i8* null)
43-
br i1 %6, label %fpcall.nil, label %fpcall.next
39+
%5 = icmp eq void (i8, i8*, i8*)* %4, null
40+
br i1 %5, label %fpcall.nil, label %fpcall.next
4441

4542
fpcall.nil:
4643
call void @runtime.nilPanic(i8* undef, i8* null)
@@ -58,9 +55,8 @@ define void @runFunc2(i8*, i32, i8, i8* %context, i8* %parentHandle) {
5855
entry:
5956
%3 = call i32 @runtime.getFuncPtr(i8* %0, i32 %1, %runtime.typecodeID* @"reflect/types.type:func:{basic:uint8}{}", i8* undef, i8* null)
6057
%4 = inttoptr i32 %3 to void (i8, i8*, i8*)*
61-
%5 = bitcast void (i8, i8*, i8*)* %4 to i8*
62-
%6 = call i1 @runtime.isnil(i8* %5, i8* undef, i8* null)
63-
br i1 %6, label %fpcall.nil, label %fpcall.next
58+
%5 = icmp eq void (i8, i8*, i8*)* %4, null
59+
br i1 %5, label %fpcall.nil, label %fpcall.next
6460

6561
fpcall.nil:
6662
call void @runtime.nilPanic(i8* undef, i8* null)

transform/testdata/func-lowering.out.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ declare void @"internal/task.start"(i32, i8*, i8*, i8*)
1919

2020
declare void @runtime.nilPanic(i8*, i8*)
2121

22-
declare i1 @runtime.isnil(i8*, i8*, i8*)
23-
2422
declare void @"main$1"(i32, i8*, i8*)
2523

2624
declare void @"main$2"(i32, i8*, i8*)
@@ -38,9 +36,8 @@ define void @runFunc1(i8*, i32, i8, i8* %context, i8* %parentHandle) {
3836
entry:
3937
%3 = icmp eq i32 %1, 0
4038
%4 = select i1 %3, void (i8, i8*, i8*)* null, void (i8, i8*, i8*)* @funcInt8
41-
%5 = bitcast void (i8, i8*, i8*)* %4 to i8*
42-
%6 = call i1 @runtime.isnil(i8* %5, i8* undef, i8* null)
43-
br i1 %6, label %fpcall.nil, label %fpcall.next
39+
%5 = icmp eq void (i8, i8*, i8*)* %4, null
40+
br i1 %5, label %fpcall.nil, label %fpcall.next
4441

4542
fpcall.nil:
4643
call void @runtime.nilPanic(i8* undef, i8* null)

0 commit comments

Comments
 (0)