diff options
| author | Joel Sing <joel@sing.id.au> | 2025-02-27 22:54:51 +1100 |
|---|---|---|
| committer | Joel Sing <joel@sing.id.au> | 2025-03-27 04:26:47 -0700 |
| commit | d37624881f60f79dfba4ef81661024bee9dfc2d3 (patch) | |
| tree | af83af8b36424b821faf933e2c3553ee09ce3b10 /src/cmd/internal/obj/riscv/obj.go | |
| parent | 1763ee199d33d2592332a29cfc3da7811718a4fd (diff) | |
| download | go-d37624881f60f79dfba4ef81661024bee9dfc2d3.tar.xz | |
cmd/internal/obj/riscv: improve constant construction
Attempt to construct large constants that have a consecutive sequence
of ones from a small negative constant, with a logical right and/or
left shift. This allows for a large range of mask like constants to be
constructed with only two or three instructions, avoiding the need to
load from memory.
Change-Id: I35a77fecdd2df0ed3f33b772d518f85119d4ff66
Reviewed-on: https://go-review.googlesource.com/c/go/+/652778
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Mark Ryan <markdryan@rivosinc.com>
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
Diffstat (limited to 'src/cmd/internal/obj/riscv/obj.go')
| -rw-r--r-- | src/cmd/internal/obj/riscv/obj.go | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index b50709729e..13f1864dea 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -2220,22 +2220,35 @@ func encodingForAs(as obj.As) (*encoding, error) { return &insData.enc, nil } -// splitShiftConst attempts to split a constant into a signed 32 bit integer -// and a corresponding left shift. -func splitShiftConst(v int64) (imm int64, lsh int, ok bool) { +// splitShiftConst attempts to split a constant into a signed 12 bit or +// 32 bit integer, with corresponding logical right shift and/or left shift. +func splitShiftConst(v int64) (imm int64, lsh int, rsh int, ok bool) { + // See if we can reconstruct this value from a signed 32 bit integer. lsh = bits.TrailingZeros64(uint64(v)) c := v >> lsh - if int64(int32(c)) != c { - return 0, 0, false + if int64(int32(c)) == c { + return c, lsh, 0, true } - return c, lsh, true + + // See if we can reconstruct this value from a small negative constant. + rsh = bits.LeadingZeros64(uint64(v)) + ones := bits.OnesCount64((uint64(v) >> lsh) >> 11) + c = signExtend(1<<11|((v>>lsh)&0x7ff), 12) + if rsh+ones+lsh+11 == 64 { + if lsh > 0 || c != -1 { + lsh += rsh + } + return c, lsh, rsh, true + } + + return 0, 0, 0, false } // isShiftConst indicates whether a constant can be represented as a signed // 32 bit integer that is left shifted. func isShiftConst(v int64) bool { - _, lsh, ok := splitShiftConst(v) - return ok && lsh > 0 + _, lsh, rsh, ok := splitShiftConst(v) + return ok && (lsh > 0 || rsh > 0) } type instruction struct { @@ -2512,16 +2525,34 @@ func instructionsForMOV(p *obj.Prog) []*instruction { // For constants larger than 32 bits in size that have trailing zeros, // use the value with the trailing zeros removed and then use a SLLI // instruction to restore the original constant. + // // For example: - // MOV $0x8000000000000000, X10 + // MOV $0x8000000000000000, X10 // becomes - // MOV $1, X10 - // SLLI $63, X10, X10 - var insSLLI *instruction + // MOV $1, X10 + // SLLI $63, X10, X10 + // + // Similarly, we can construct large constants that have a consecutive + // sequence of ones from a small negative constant, with a right and/or + // left shift. + // + // For example: + // MOV $0x000fffffffffffda, X10 + // becomes + // MOV $-19, X10 + // SLLI $13, X10 + // SRLI $12, X10 + // + var insSLLI, insSRLI *instruction if err := immIFits(ins.imm, 32); err != nil { - if c, lsh, ok := splitShiftConst(ins.imm); ok { + if c, lsh, rsh, ok := splitShiftConst(ins.imm); ok { ins.imm = c - insSLLI = &instruction{as: ASLLI, rd: ins.rd, rs1: ins.rd, imm: int64(lsh)} + if lsh > 0 { + insSLLI = &instruction{as: ASLLI, rd: ins.rd, rs1: ins.rd, imm: int64(lsh)} + } + if rsh > 0 { + insSRLI = &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: int64(rsh)} + } } } @@ -2548,6 +2579,9 @@ func instructionsForMOV(p *obj.Prog) []*instruction { if insSLLI != nil { inss = append(inss, insSLLI) } + if insSRLI != nil { + inss = append(inss, insSRLI) + } case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG: p.Ctxt.Diag("%v: constant load must target register", p) |
