]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/riscv: avoid obj.Prog rewriting for load instructions
authorJoel Sing <joel@sing.id.au>
Wed, 18 Aug 2021 18:14:52 +0000 (18:14 +0000)
committerJoel Sing <joel@sing.id.au>
Sat, 4 Sep 2021 10:42:46 +0000 (10:42 +0000)
Rather than rewriting the obj.Prog for a load instruction, generate the
appropriate machine instruction sequence directly.

Change-Id: Iba656dbf2dff2bce02aa221d9a5cad7b7c4630d8
Reviewed-on: https://go-review.googlesource.com/c/go/+/344451
Trust: Joel Sing <joel@sing.id.au>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/cmd/internal/obj/riscv/cpu.go
src/cmd/internal/obj/riscv/obj.go

index b1324b62a0377ea415e6654258a01c10c149e6e3..1519dc1a63811ae2eb2bcd93ffe71100b3444201 100644 (file)
@@ -256,15 +256,19 @@ var RISCV64DWARFRegisters = map[int16]int16{
 
 // Prog.Mark flags.
 const (
+       // USES_REG_TMP indicates that a machine instruction generated from the
+       // corresponding *obj.Prog uses the temporary register.
+       USES_REG_TMP = 1 << iota
+
        // NEED_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that
        // it is the first instruction in an AUIPC + I-type pair that needs a
        // R_RISCV_PCREL_ITYPE relocation.
-       NEED_PCREL_ITYPE_RELOC = 1 << 0
+       NEED_PCREL_ITYPE_RELOC
 
        // NEED_PCREL_STYPE_RELOC is set on AUIPC instructions to indicate that
        // it is the first instruction in an AUIPC + S-type pair that needs a
        // R_RISCV_PCREL_STYPE relocation.
-       NEED_PCREL_STYPE_RELOC = 1 << 1
+       NEED_PCREL_STYPE_RELOC
 )
 
 // RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files
index 3ccd4895734f5a092b097d30562c2b9acd553dae..3d304c1b421ff1174108c4b84beeaf6ab5ad0658 100644 (file)
@@ -795,38 +795,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        p.Reg = q.Reg
                        p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
 
-               // <load> $imm, REG, TO (load $imm+(REG), TO)
-               case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
-                       low, high, err := Split32BitImmediate(p.From.Offset)
-                       if err != nil {
-                               ctxt.Diag("%v: constant %d too large", p, p.From.Offset)
-                       }
-                       if high == 0 {
-                               break // no need to split
-                       }
-                       q := *p
-
-                       // LUI $high, TMP
-                       // ADD TMP, REG, TMP
-                       // <load> $low, TMP, TO
-                       p.As = ALUI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
-                       p.Reg = 0
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Spadj = 0 // needed if TO is SP
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADD
-                       p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Reg = q.From.Reg
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = q.As
-                       p.To = q.To
-                       p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low}
-                       p.Reg = obj.REG_NONE
-
                // <store> $imm, REG, TO (store $imm+(TO), REG)
                case ASD, ASB, ASH, ASW, AFSW, AFSD:
                        low, high, err := Split32BitImmediate(p.To.Offset)
@@ -1793,6 +1761,10 @@ func (ins *instruction) validate(ctxt *obj.Link) {
        enc.validate(ctxt, ins)
 }
 
+func (ins *instruction) usesRegTmp() bool {
+       return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
+}
+
 // instructionForProg returns the default *obj.Prog to instruction mapping.
 func instructionForProg(p *obj.Prog) *instruction {
        ins := &instruction{
@@ -1808,6 +1780,43 @@ func instructionForProg(p *obj.Prog) *instruction {
        return ins
 }
 
+func instructionsForLoad(p *obj.Prog) []*instruction {
+       if p.From.Type != obj.TYPE_MEM {
+               p.Ctxt.Diag("%v requires memory for source", p)
+               return nil
+       }
+
+       switch p.As {
+       case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
+       default:
+               p.Ctxt.Diag("%v: unknown load instruction %v", p, p.As)
+               return nil
+       }
+
+       // <load> $imm, REG, TO (load $imm+(REG), TO)
+       ins := instructionForProg(p)
+       ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
+       ins.imm = p.From.Offset
+
+       low, high, err := Split32BitImmediate(ins.imm)
+       if err != nil {
+               p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
+               return nil
+       }
+       if high == 0 {
+               return []*instruction{ins}
+       }
+
+       // LUI $high, TMP
+       // ADD TMP, REG, TMP
+       // <load> $low, TMP, TO
+       insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
+       insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rs1}
+       ins.rs1, ins.imm = REG_TMP, low
+
+       return []*instruction{insLUI, insADD, ins}
+}
+
 // instructionsForMOV returns the machine instructions for an *obj.Prog that
 // uses a MOV pseudo-instruction.
 func instructionsForMOV(p *obj.Prog) []*instruction {
@@ -1928,12 +1937,7 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                return instructionsForMOV(p)
 
        case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
-               if p.From.Type != obj.TYPE_MEM {
-                       p.Ctxt.Diag("%v requires memory for source", p)
-                       return nil
-               }
-               ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
-               ins.imm = p.From.Offset
+               return instructionsForLoad(p)
 
        case ASW, ASH, ASB, ASD, AFSW, AFSD:
                if p.To.Type != obj.TYPE_MEM {
@@ -2104,9 +2108,13 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 
                for _, ins := range instructionsForProg(p) {
                        ic, err := ins.encode()
-                       if err == nil {
-                               symcode = append(symcode, ic)
+                       if err != nil {
+                               break
+                       }
+                       if ins.usesRegTmp() {
+                               p.Mark |= USES_REG_TMP
                        }
+                       symcode = append(symcode, ic)
                }
        }
        cursym.Size = int64(4 * len(symcode))
@@ -2120,7 +2128,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 }
 
 func isUnsafePoint(p *obj.Prog) bool {
-       return p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
+       return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
 }
 
 var LinkRISCV64 = obj.LinkArch{