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.
Этот коммит содержится в:
Ayke van Laethem 2020-04-04 15:47:22 +02:00 коммит произвёл Ayke
родитель f06d7d1bd6
коммит 46345aade6

Просмотреть файл

@ -2207,7 +2207,19 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
case *types.Interface: case *types.Interface:
switch op { switch op {
case token.EQL, token.NEQ: // ==, != 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 { if op == token.NEQ {
result = b.CreateNot(result, "") result = b.CreateNot(result, "")
} }