Convert subtraction from const to a negated ADDI with negative const
value, where possible. At worst this avoids a register load and uses
the same number of instructions. At best, this allows for further
optimisation to occur, particularly where equality is involved.
For example, this sequence:
li t0,-1
sub t1,t0,a0
snez t1,t1
Becomes:
addi t0,a0,1
snez t0,t0
Removes more than 2000 instructions from the Go binary on linux/riscv64.
Change-Id: I68f3be897bc645d4a8fa3ab3cef165a00a74df19
Reviewed-on: https://go-review.googlesource.com/c/go/+/426263
Reviewed-by: Meng Zhuo <mzh@golangcn.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Joel Sing <joel@sing.id.au>
(SRL x (MOVDconst [val])) => (SRLI [int64(val&63)] x)
(SRA x (MOVDconst [val])) => (SRAI [int64(val&63)] x)
-// Convert subtraction of a const into ADDI with negative immediate, where possible.
+// Convert const subtraction into ADDI with negative immediate, where possible.
(SUB x (MOVDconst [val])) && is32Bit(-val) => (ADDI [-val] x)
+(SUB <t> (MOVDconst [val]) y) && is32Bit(-val) => (NEG (ADDI <t> [-val] y))
// Subtraction of zero.
(SUB x (MOVDconst [0])) => x
func rewriteValueRISCV64_OpRISCV64SUB(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
+ b := v.Block
// match: (SUB x (MOVDconst [val]))
// cond: is32Bit(-val)
// result: (ADDI [-val] x)
v.AddArg(x)
return true
}
+ // match: (SUB <t> (MOVDconst [val]) y)
+ // cond: is32Bit(-val)
+ // result: (NEG (ADDI <t> [-val] y))
+ for {
+ t := v.Type
+ if v_0.Op != OpRISCV64MOVDconst {
+ break
+ }
+ val := auxIntToInt64(v_0.AuxInt)
+ y := v_1
+ if !(is32Bit(-val)) {
+ break
+ }
+ v.reset(OpRISCV64NEG)
+ v0 := b.NewValue0(v.Pos, OpRISCV64ADDI, t)
+ v0.AuxInt = int64ToAuxInt(-val)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
// match: (SUB x (MOVDconst [0]))
// result: x
for {