On riscv64, subtraction from a constant is typically implemented as an
ADDI with the negative constant, followed by a negation. However this can
lead to multiple NEG/ADDI/NEG sequences that can be optimised out.
For example, runtime.(*_panic).nextDefer currently contains:
lbu t0, 0(t0)
addi t0, t0, -8
neg t0, t0
addi t0, t0, -7
neg t0, t0
Which is now optimised to:
lbu t0, 0(t0)
addi t0, t0, -1
Change-Id: Idf5815e6db2e3705cc4a4811ca9130a064ae3d80
Reviewed-on: https://go-review.googlesource.com/c/go/+/652318
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Ryan <markdryan@rivosinc.com>
Reviewed-by: David Chase <drchase@google.com>
// Double negation.
(NEG (NEG x)) => x
+(NEG <t> s:(ADDI [val] (NEG x))) && s.Uses == 1 && is32Bit(-val) => (ADDI [-val] x)
// Addition of zero or two constants.
(ADDI [0] x) => x
v.copyOf(x)
return true
}
+ // match: (NEG <t> s:(ADDI [val] (NEG x)))
+ // cond: s.Uses == 1 && is32Bit(-val)
+ // result: (ADDI [-val] x)
+ for {
+ s := v_0
+ if s.Op != OpRISCV64ADDI {
+ break
+ }
+ val := auxIntToInt64(s.AuxInt)
+ s_0 := s.Args[0]
+ if s_0.Op != OpRISCV64NEG {
+ break
+ }
+ x := s_0.Args[0]
+ if !(s.Uses == 1 && is32Bit(-val)) {
+ break
+ }
+ v.reset(OpRISCV64ADDI)
+ v.AuxInt = int64ToAuxInt(-val)
+ v.AddArg(x)
+ return true
+ }
// match: (NEG (MOVDconst [x]))
// result: (MOVDconst [-x])
for {
func SubFromConstNeg(a int) int {
// ppc64x: `ADD\t[$]40,\sR[0-9]+,\sR`
- // riscv64: "NEG","ADDI\t\\$-40","NEG"
+ // riscv64: "ADDI\t\\$40",-"NEG"
c := 40 - (-a)
return c
}