Recognize runtime.newobject and don't Zero or NilCheck it.
Fixes #15914 (?)
Updates #15390.
TBD: add test
Change-Id: Ia3bfa5c2ddbe2c27c92d9f68534a713b5ce95934
Reviewed-on: https://go-review.googlesource.com/27930
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
arch string // "amd64", etc.
IntSize int64 // 4 or 8
PtrSize int64 // 4 or 8
- lowerBlock func(*Block) bool // lowering function
+ lowerBlock func(*Block, *Config) bool // lowering function
lowerValue func(*Value, *Config) bool // lowering function
registers []Register // machine registers
gpRegMask regMask // general purpose integer register mask
(Div64F x (Const64F [f2i(-1)])) -> (Neg32F x)
(Sqrt (Const64F [c])) -> (Const64F [f2i(math.Sqrt(i2f(c)))])
+
+// recognize runtime.newobject and don't Zero/Nilcheck it
+(Zero (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _)) mem2)
+ && c == config.ctxt.FixedFrameSize() + config.PtrSize // offset of return value
+ && mem2 == mem
+ && isSameSym(sym, "runtime.newobject")
+ -> mem
+(Check (NilCheck (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _)) _) succ)
+ && c == config.ctxt.FixedFrameSize() + config.PtrSize // offset of return value
+ && isSameSym(sym, "runtime.newobject")
+ -> (Plain nil succ)
+(Check (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _))) _) succ)
+ && c == config.ctxt.FixedFrameSize() + config.PtrSize // offset of return value
+ && isSameSym(sym, "runtime.newobject")
+ -> (Plain nil succ)
// Generate block rewrite function. There are only a few block types
// so we can make this one function with a switch.
- fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
+ fmt.Fprintf(w, "func rewriteBlock%s(b *Block, config *Config) bool {\n", arch.name)
fmt.Fprintf(w, "switch b.Kind {\n")
ops = nil
for op := range blockrules {
"path/filepath"
)
-func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
+func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Config) bool) {
// repeat rewrites until we find no more rewrites
var curb *Block
var curv *Value
}
}
curb = b
- if rb(b) {
+ if rb(b, config) {
change = true
}
curb = nil
return ok
}
+// isSameSym returns whether sym is the same as the given named symbol
+func isSameSym(sym interface{}, name string) bool {
+ s, ok := sym.(fmt.Stringer)
+ return ok && s.String() == name
+}
+
// nlz returns the number of leading zeros.
func nlz(x int64) int64 {
// log2(0) == 1, so nlz(0) == 64
return true
}
}
-func rewriteBlock386(b *Block) bool {
+func rewriteBlock386(b *Block, config *Config) bool {
switch b.Kind {
case Block386EQ:
// match: (EQ (InvertFlags cmp) yes no)
return true
}
}
-func rewriteBlockAMD64(b *Block) bool {
+func rewriteBlockAMD64(b *Block, config *Config) bool {
switch b.Kind {
case BlockAMD64EQ:
// match: (EQ (InvertFlags cmp) yes no)
return true
}
}
-func rewriteBlockARM(b *Block) bool {
+func rewriteBlockARM(b *Block, config *Config) bool {
switch b.Kind {
case BlockARMEQ:
// match: (EQ (FlagEQ) yes no)
return true
}
}
-func rewriteBlockARM64(b *Block) bool {
+func rewriteBlockARM64(b *Block, config *Config) bool {
switch b.Kind {
case BlockARM64EQ:
// match: (EQ (FlagEQ) yes no)
return true
}
}
-func rewriteBlockMIPS64(b *Block) bool {
+func rewriteBlockMIPS64(b *Block, config *Config) bool {
switch b.Kind {
case BlockMIPS64EQ:
// match: (EQ (FPFlagTrue cmp) yes no)
return true
}
}
-func rewriteBlockPPC64(b *Block) bool {
+func rewriteBlockPPC64(b *Block, config *Config) bool {
switch b.Kind {
case BlockPPC64EQ:
// match: (EQ (FlagEQ) yes no)
}
return false
}
-func rewriteBlockdec(b *Block) bool {
+func rewriteBlockdec(b *Block, config *Config) bool {
switch b.Kind {
}
return false
return true
}
}
-func rewriteBlockdec64(b *Block) bool {
+func rewriteBlockdec64(b *Block, config *Config) bool {
switch b.Kind {
}
return false
return rewriteValuegeneric_OpXor64(v, config)
case OpXor8:
return rewriteValuegeneric_OpXor8(v, config)
+ case OpZero:
+ return rewriteValuegeneric_OpZero(v, config)
}
return false
}
}
return false
}
-func rewriteBlockgeneric(b *Block) bool {
+func rewriteValuegeneric_OpZero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Zero (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _)) mem2)
+ // cond: c == config.ctxt.FixedFrameSize() + config.PtrSize && mem2 == mem && isSameSym(sym, "runtime.newobject")
+ // result: mem
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpOffPtr {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_0_0 := v_0_0.Args[0]
+ if v_0_0_0.Op != OpSP {
+ break
+ }
+ mem := v_0.Args[1]
+ if mem.Op != OpStaticCall {
+ break
+ }
+ sym := mem.Aux
+ mem2 := v.Args[1]
+ if !(c == config.ctxt.FixedFrameSize()+config.PtrSize && mem2 == mem && isSameSym(sym, "runtime.newobject")) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteBlockgeneric(b *Block, config *Config) bool {
switch b.Kind {
case BlockCheck:
// match: (Check (NilCheck (GetG _) _) next)
_ = next
return true
}
+ // match: (Check (NilCheck (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _)) _) succ)
+ // cond: c == config.ctxt.FixedFrameSize() + config.PtrSize && isSameSym(sym, "runtime.newobject")
+ // result: (Plain nil succ)
+ for {
+ v := b.Control
+ if v.Op != OpNilCheck {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpOffPtr {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_0_0 := v_0_0.Args[0]
+ if v_0_0_0.Op != OpSP {
+ break
+ }
+ mem := v_0.Args[1]
+ if mem.Op != OpStaticCall {
+ break
+ }
+ sym := mem.Aux
+ succ := b.Succs[0]
+ if !(c == config.ctxt.FixedFrameSize()+config.PtrSize && isSameSym(sym, "runtime.newobject")) {
+ break
+ }
+ b.Kind = BlockPlain
+ b.SetControl(nil)
+ _ = succ
+ return true
+ }
+ // match: (Check (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem:(StaticCall {sym} _))) _) succ)
+ // cond: c == config.ctxt.FixedFrameSize() + config.PtrSize && isSameSym(sym, "runtime.newobject")
+ // result: (Plain nil succ)
+ for {
+ v := b.Control
+ if v.Op != OpNilCheck {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpOffPtr {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpLoad {
+ break
+ }
+ v_0_0_0 := v_0_0.Args[0]
+ if v_0_0_0.Op != OpOffPtr {
+ break
+ }
+ c := v_0_0_0.AuxInt
+ v_0_0_0_0 := v_0_0_0.Args[0]
+ if v_0_0_0_0.Op != OpSP {
+ break
+ }
+ mem := v_0_0.Args[1]
+ if mem.Op != OpStaticCall {
+ break
+ }
+ sym := mem.Aux
+ succ := b.Succs[0]
+ if !(c == config.ctxt.FixedFrameSize()+config.PtrSize && isSameSym(sym, "runtime.newobject")) {
+ break
+ }
+ b.Kind = BlockPlain
+ b.SetControl(nil)
+ _ = succ
+ return true
+ }
case BlockIf:
// match: (If (Not cond) yes no)
// cond:
}
// implementation of new builtin
+// compiler (both frontend and SSA backend) knows the signature
+// of this function
func newobject(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true)
}