diff options
| author | Joel Sing <joel@sing.id.au> | 2025-12-03 00:42:54 +1100 |
|---|---|---|
| committer | Joel Sing <joel@sing.id.au> | 2026-03-10 05:05:15 -0700 |
| commit | 7f7e4942f1a83aa60c88e7536cfc4166a4c65c43 (patch) | |
| tree | 9235baf2a037966abc8ce327971d34522ec65d71 /src/cmd/internal | |
| parent | 0a0c9c88fdee8317c1f9e10c5e61d3cf7428c7c1 (diff) | |
| download | go-7f7e4942f1a83aa60c88e7536cfc4166a4c65c43.tar.xz | |
cmd/internal/obj/riscv: factor out constant materialisation code
Pull the constant materialisation code out into its own function, which
reduces indentation and improves readability.
Change-Id: Ia06baefa99c8f1a738c1b13d1a8b27111fa948b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/748961
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Ryan <markdryan@meta.com>
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src/cmd/internal')
| -rw-r--r-- | src/cmd/internal/obj/riscv/obj.go | 130 |
1 files changed, 69 insertions, 61 deletions
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index ac2b54187d..28bba008f7 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -3883,6 +3883,74 @@ func instructionsForTLSStore(p *obj.Prog) []*instruction { return instructionsForTLS(p, ins) } +func instructionsForMOVConst(p *obj.Prog) []*instruction { + ins := instructionForProg(p) + inss := []*instruction{ins} + + // 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 + // becomes + // 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, rsh, ok := splitShiftConst(ins.imm); ok { + ins.imm = c + 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)} + } + } + } + + low, high, err := Split32BitImmediate(ins.imm) + if err != nil { + p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err) + return nil + } + + // MOV $c, R -> ADD $c, ZERO, R + ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low + + // LUI is only necessary if the constant does not fit in 12 bits. + if high != 0 { + // LUI top20bits(c), R + // ADD bottom12bits(c), R, R + insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high} + inss = []*instruction{insLUI} + if low != 0 { + ins.as, ins.rs1 = AADDIW, ins.rd + inss = append(inss, ins) + } + } + if insSLLI != nil { + inss = append(inss, insSLLI) + } + if insSRLI != nil { + inss = append(inss, insSRLI) + } + + return inss +} + // instructionsForMOV returns the machine instructions for an *obj.Prog that // uses a MOV pseudo-instruction. func instructionsForMOV(p *obj.Prog) []*instruction { @@ -3901,67 +3969,7 @@ func instructionsForMOV(p *obj.Prog) []*instruction { p.Ctxt.Diag("%v: unsupported constant load", p) return nil } - - // 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 - // becomes - // 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, rsh, ok := splitShiftConst(ins.imm); ok { - ins.imm = c - 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)} - } - } - } - - low, high, err := Split32BitImmediate(ins.imm) - if err != nil { - p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err) - return nil - } - - // MOV $c, R -> ADD $c, ZERO, R - ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low - - // LUI is only necessary if the constant does not fit in 12 bits. - if high != 0 { - // LUI top20bits(c), R - // ADD bottom12bits(c), R, R - insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high} - inss = []*instruction{insLUI} - if low != 0 { - ins.as, ins.rs1 = AADDIW, ins.rd - inss = append(inss, ins) - } - } - if insSLLI != nil { - inss = append(inss, insSLLI) - } - if insSRLI != nil { - inss = append(inss, insSRLI) - } + return instructionsForMOVConst(p) case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG: p.Ctxt.Diag("%v: constant load must target register", p) |
