From ba8c94b5f255bf84d05cf90d3d66621ffd2e0fab Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 5 Sep 2022 03:03:35 +1000 Subject: [PATCH] cmd/compile: convert SLT/SLTU with constant into immediate form on riscv64 Convert SLT/SLTU with a suitably valued constant into a SLTI/SLTIU instruction. This can reduce instructions and avoid register loads. Now that we generate more SLTI/SLTIU instructions, absorb these into branches when it makes sense to do so. Removes more than 800 instructions from the Go binary on linux/riscv64. Change-Id: I42c4e00486697acd4da7669d441b5690795f18ae Reviewed-on: https://go-review.googlesource.com/c/go/+/428499 Reviewed-by: Wayne Zuo Run-TryBot: Joel Sing Reviewed-by: Cherry Mui TryBot-Result: Gopher Robot Reviewed-by: Joedian Reid --- .../compile/internal/ssa/_gen/RISCV64.rules | 19 +++-- .../compile/internal/ssa/rewriteRISCV64.go | 78 +++++++++++++++++++ 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules index 9882505b6b..6119f3482b 100644 --- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules @@ -2,13 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Optimizations TODO: -// * Use SLTI and SLTIU for comparisons to constants, instead of SLT/SLTU with constants in registers -// * Use the zero register instead of moving 0 into a register. -// * Add rules to avoid generating a temp bool value for (If (SLT[U] ...) ...). -// * Arrange for non-trivial Zero and Move lowerings to use aligned loads and stores. -// * Avoid using Neq32 for writeBarrier.enabled checks. - // Lowering arithmetic (Add64 ...) => (ADD ...) (AddPtr ...) => (ADD ...) @@ -626,6 +619,10 @@ (BNEZ (SLT x y) yes no) => (BLT x y yes no) (BEQZ (SLTU x y) yes no) => (BGEU x y yes no) (BNEZ (SLTU x y) yes no) => (BLTU x y yes no) +(BEQZ (SLTI [x] y) yes no) => (BGE y (MOVDconst [x]) yes no) +(BNEZ (SLTI [x] y) yes no) => (BLT y (MOVDconst [x]) yes no) +(BEQZ (SLTIU [x] y) yes no) => (BGEU y (MOVDconst [x]) yes no) +(BNEZ (SLTIU [x] y) yes no) => (BLTU y (MOVDconst [x]) yes no) // Convert branch with zero to more optimal branch zero. (BEQ (MOVDconst [0]) cond yes no) => (BEQZ cond yes no) @@ -763,9 +760,11 @@ (AND (MOVDconst [val]) x) && is32Bit(val) => (ANDI [val] x) (OR (MOVDconst [val]) x) && is32Bit(val) => (ORI [val] x) (XOR (MOVDconst [val]) x) && is32Bit(val) => (XORI [val] x) -(SLL x (MOVDconst [val])) => (SLLI [int64(val&63)] x) -(SRL x (MOVDconst [val])) => (SRLI [int64(val&63)] x) -(SRA x (MOVDconst [val])) => (SRAI [int64(val&63)] x) +(SLL x (MOVDconst [val])) => (SLLI [int64(val&63)] x) +(SRL x (MOVDconst [val])) => (SRLI [int64(val&63)] x) +(SRA x (MOVDconst [val])) => (SRAI [int64(val&63)] x) +(SLT x (MOVDconst [val])) && val >= -2048 && val <= 2047 => (SLTI [val] x) +(SLTU x (MOVDconst [val])) && val >= -2048 && val <= 2047 => (SLTIU [val] x) // Convert const subtraction into ADDI with negative immediate, where possible. (SUB x (MOVDconst [val])) && is32Bit(-val) => (ADDI [-val] x) diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index ff40a7b6ef..31ec233e61 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -5618,6 +5618,23 @@ func rewriteValueRISCV64_OpRISCV64SLLI(v *Value) bool { func rewriteValueRISCV64_OpRISCV64SLT(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + // match: (SLT x (MOVDconst [val])) + // cond: val >= -2048 && val <= 2047 + // result: (SLTI [val] x) + for { + x := v_0 + if v_1.Op != OpRISCV64MOVDconst { + break + } + val := auxIntToInt64(v_1.AuxInt) + if !(val >= -2048 && val <= 2047) { + break + } + v.reset(OpRISCV64SLTI) + v.AuxInt = int64ToAuxInt(val) + v.AddArg(x) + return true + } // match: (SLT x x) // result: (MOVDconst [0]) for { @@ -5730,6 +5747,23 @@ func rewriteValueRISCV64_OpRISCV64SLTIU(v *Value) bool { func rewriteValueRISCV64_OpRISCV64SLTU(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + // match: (SLTU x (MOVDconst [val])) + // cond: val >= -2048 && val <= 2047 + // result: (SLTIU [val] x) + for { + x := v_0 + if v_1.Op != OpRISCV64MOVDconst { + break + } + val := auxIntToInt64(v_1.AuxInt) + if !(val >= -2048 && val <= 2047) { + break + } + v.reset(OpRISCV64SLTIU) + v.AuxInt = int64ToAuxInt(val) + v.AddArg(x) + return true + } // match: (SLTU x x) // result: (MOVDconst [0]) for { @@ -8282,6 +8316,28 @@ func rewriteBlockRISCV64(b *Block) bool { b.resetWithControl2(BlockRISCV64BGEU, x, y) return true } + // match: (BEQZ (SLTI [x] y) yes no) + // result: (BGE y (MOVDconst [x]) yes no) + for b.Controls[0].Op == OpRISCV64SLTI { + v_0 := b.Controls[0] + x := auxIntToInt64(v_0.AuxInt) + y := v_0.Args[0] + v0 := b.NewValue0(b.Pos, OpRISCV64MOVDconst, typ.UInt64) + v0.AuxInt = int64ToAuxInt(x) + b.resetWithControl2(BlockRISCV64BGE, y, v0) + return true + } + // match: (BEQZ (SLTIU [x] y) yes no) + // result: (BGEU y (MOVDconst [x]) yes no) + for b.Controls[0].Op == OpRISCV64SLTIU { + v_0 := b.Controls[0] + x := auxIntToInt64(v_0.AuxInt) + y := v_0.Args[0] + v0 := b.NewValue0(b.Pos, OpRISCV64MOVDconst, typ.UInt64) + v0.AuxInt = int64ToAuxInt(x) + b.resetWithControl2(BlockRISCV64BGEU, y, v0) + return true + } case BlockRISCV64BGE: // match: (BGE (MOVDconst [0]) cond yes no) // result: (BLEZ cond yes no) @@ -8437,6 +8493,28 @@ func rewriteBlockRISCV64(b *Block) bool { b.resetWithControl2(BlockRISCV64BLTU, x, y) return true } + // match: (BNEZ (SLTI [x] y) yes no) + // result: (BLT y (MOVDconst [x]) yes no) + for b.Controls[0].Op == OpRISCV64SLTI { + v_0 := b.Controls[0] + x := auxIntToInt64(v_0.AuxInt) + y := v_0.Args[0] + v0 := b.NewValue0(b.Pos, OpRISCV64MOVDconst, typ.UInt64) + v0.AuxInt = int64ToAuxInt(x) + b.resetWithControl2(BlockRISCV64BLT, y, v0) + return true + } + // match: (BNEZ (SLTIU [x] y) yes no) + // result: (BLTU y (MOVDconst [x]) yes no) + for b.Controls[0].Op == OpRISCV64SLTIU { + v_0 := b.Controls[0] + x := auxIntToInt64(v_0.AuxInt) + y := v_0.Args[0] + v0 := b.NewValue0(b.Pos, OpRISCV64MOVDconst, typ.UInt64) + v0.AuxInt = int64ToAuxInt(x) + b.resetWithControl2(BlockRISCV64BLTU, y, v0) + return true + } case BlockIf: // match: (If cond yes no) // result: (BNEZ (MOVBUreg cond) yes no) -- 2.50.0