diff options
author | Ayke van Laethem <[email protected]> | 2020-04-04 15:47:22 +0200 |
---|---|---|
committer | Ayke <[email protected]> | 2020-04-04 22:47:21 +0200 |
commit | 46345aade6295cbe22c0911f09b1f4e9358bb841 (patch) | |
tree | 6f320745faed57a489f4f60f88965f424e47b603 | |
parent | f06d7d1bd6cf5d5231dde4de8ef4ae5ecd908074 (diff) | |
download | tinygo-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.go | 14 |
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, "") } |