aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2020-04-04 15:47:22 +0200
committerAyke <[email protected]>2020-04-04 22:47:21 +0200
commit46345aade6295cbe22c0911f09b1f4e9358bb841 (patch)
tree6f320745faed57a489f4f60f88965f424e47b603
parentf06d7d1bd6cf5d5231dde4de8ef4ae5ecd908074 (diff)
downloadtinygo-46345aade6295cbe22c0911f09b1f4e9358bb841.tar.gz
tinygo-46345aade6295cbe22c0911f09b1f4e9358bb841.zip
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.
-rw-r--r--compiler/compiler.go14
1 files changed, 13 insertions, 1 deletions
diff --git a/compiler/compiler.go b/compiler/compiler.go
index b49befaa9..0464d1105 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, "")
}