From 46345aade6295cbe22c0911f09b1f4e9358bb841 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 4 Apr 2020 15:47:22 +0200 Subject: [PATCH] compiler: optimize comparing interface values against nil This is a very common case. Avoiding a runtime.interfaceEqual call leads to a very big reduction in code size in some cases (while it doesn't affect many other examples). A number of driver smoke tests are reduced by about 4kB just with this optimization. I found this issue while looking into automatically calculating the required amount of stack space for goroutines. The runtime.interfaceEqual function is recursive, so it is best avoided. --- compiler/compiler.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index b49befaa..0464d110 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -2207,7 +2207,19 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va case *types.Interface: switch op { case token.EQL, token.NEQ: // ==, != - result := b.createRuntimeCall("interfaceEqual", []llvm.Value{x, y}, "") + nilInterface := llvm.ConstNull(x.Type()) + var result llvm.Value + if x == nilInterface || y == nilInterface { + // An interface value is compared against nil. + // This is a very common case and is easy to optimize: simply + // compare the typecodes (of which one is nil). + typecodeX := b.CreateExtractValue(x, 0, "") + typecodeY := b.CreateExtractValue(y, 0, "") + result = b.CreateICmp(llvm.IntEQ, typecodeX, typecodeY, "") + } else { + // Fall back to a full interface comparison. + result = b.createRuntimeCall("interfaceEqual", []llvm.Value{x, y}, "") + } if op == token.NEQ { result = b.CreateNot(result, "") }