]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/riscv: avoid obj.Prog rewriting for address to register loads
authorJoel Sing <joel@sing.id.au>
Fri, 20 Aug 2021 17:04:35 +0000 (17:04 +0000)
committerJoel Sing <joel@sing.id.au>
Sat, 4 Sep 2021 19:33:36 +0000 (19:33 +0000)
Rather than rewriting the obj.Prog for a MOV pseudo-instruction targeting
an address to register load, generate the appropriate machine instruction
sequence directly.

Change-Id: I507195b6d24ff3253eadcc807ddbe27dca97d220
Reviewed-on: https://go-review.googlesource.com/c/go/+/344456
Trust: Joel Sing <joel@sing.id.au>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/cmd/internal/obj/riscv/obj.go

index d0574edc419974e8dffe13dd9c49e6f095185e28..b4aded3768c4c60071fbc36a1000ff3ecf934c58 100644 (file)
@@ -278,39 +278,15 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
                        ctxt.Diag("%v: constant load must target register", p)
                }
 
-       case obj.TYPE_ADDR: // MOV $sym+off(SP/SB), R
+       case obj.TYPE_ADDR:
                if p.To.Type != obj.TYPE_REG || p.As != AMOV {
                        ctxt.Diag("unsupported addr MOV at %v", p)
                }
                switch p.From.Name {
-               case obj.NAME_EXTERN, obj.NAME_STATIC:
-                       // AUIPC $off_hi, R
-                       // ADDI $off_lo, R
-                       to := p.To
+               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
 
-                       p.As = AAUIPC
+               case obj.NAME_EXTERN, obj.NAME_STATIC:
                        p.Mark |= NEED_PCREL_ITYPE_RELOC
-                       p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-                       p.Reg = 0
-                       p.To = to
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADDI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST}
-                       p.Reg = to.Reg
-                       p.To = to
-
-               case obj.NAME_PARAM, obj.NAME_AUTO:
-                       p.As = AADDI
-                       p.Reg = REG_SP
-                       p.From.Type = obj.TYPE_CONST
-
-               case obj.NAME_NONE:
-                       p.As = AADDI
-                       p.Reg = p.From.Reg
-                       p.From.Type = obj.TYPE_CONST
-                       p.From.Reg = 0
 
                default:
                        ctxt.Diag("bad addr MOV from name %v at %v", p.From.Name, p)
@@ -1645,6 +1621,57 @@ func instructionForProg(p *obj.Prog) *instruction {
        return ins
 }
 
+// instructionsForOpImmediate returns the machine instructions for a immedate
+// operand. The instruction is specified by as and the source register is
+// specified by rs, instead of the obj.Prog.
+func instructionsForOpImmediate(p *obj.Prog, as obj.As, rs int16) []*instruction {
+       // <opi> $imm, REG, TO
+       ins := instructionForProg(p)
+       ins.as, ins.rs1 = as, uint32(rs)
+
+       low, high, err := Split32BitImmediate(ins.imm)
+       if err != nil {
+               p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
+               return nil
+       }
+       if high == 0 {
+               return []*instruction{ins}
+       }
+
+       // Split into two additions, if possible.
+       if ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
+               imm0 := ins.imm / 2
+               imm1 := ins.imm - imm0
+
+               // ADDI $(imm/2), REG, TO
+               // ADDI $(imm-imm/2), TO, TO
+               ins.imm = imm0
+               insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
+               return []*instruction{ins, insADDI}
+       }
+
+       // LUI $high, TMP
+       // ADDI $low, TMP, TMP
+       // <op> TMP, REG, TO
+       insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
+       insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
+       switch ins.as {
+       case AADDI:
+               ins.as = AADD
+       case AANDI:
+               ins.as = AAND
+       case AORI:
+               ins.as = AOR
+       case AXORI:
+               ins.as = AXOR
+       default:
+               p.Ctxt.Diag("unsupported immediate instruction %v for splitting", p)
+               return nil
+       }
+       ins.rs2 = REG_TMP
+       return []*instruction{insLUI, insADDIW, ins}
+}
+
 // instructionsForLoad returns the machine instructions for a load. The load
 // instruction is specified by as and the base/source register is specified
 // by rs, instead of the obj.Prog.
@@ -1797,6 +1824,9 @@ func instructionsForMOV(p *obj.Prog) []*instruction {
                        inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From))
 
                case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
                        // AUIPC $off_hi, Rd
                        // L $off_lo, Rd, Rd
                        insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
@@ -1817,6 +1847,9 @@ func instructionsForMOV(p *obj.Prog) []*instruction {
                        inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
 
                case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
                        // AUIPC $off_hi, Rtmp
                        // S $off_lo, Rtmp, Rd
                        insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
@@ -1824,6 +1857,24 @@ func instructionsForMOV(p *obj.Prog) []*instruction {
                        inss = []*instruction{insAUIPC, ins}
                }
 
+       case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
+               // MOV $sym+off(SP/SB), R
+
+               switch p.From.Name {
+               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
+                       inss = instructionsForOpImmediate(p, AADDI, addrToReg(p.From))
+
+               case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
+                       // AUIPC $off_hi, R
+                       // ADDI $off_lo, R
+                       insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
+                       ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, ins.rd, obj.REG_NONE, 0
+                       inss = []*instruction{insAUIPC, ins}
+               }
+
        default:
                // If we get here with a MOV pseudo-instruction it is going to
                // remain unhandled. For now we trust rewriteMOV to catch these.
@@ -1891,49 +1942,7 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
 
        case AADDI, AANDI, AORI, AXORI:
-               // <opi> $imm, REG, TO
-               low, high, err := Split32BitImmediate(ins.imm)
-               if err != nil {
-                       p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
-                       return nil
-               }
-               if high == 0 {
-                       break
-               }
-
-               // Split into two additions if possible.
-               if ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
-                       imm0 := ins.imm / 2
-                       imm1 := ins.imm - imm0
-
-                       // ADDI $(imm/2), REG, TO
-                       // ADDI $(imm-imm/2), TO, TO
-                       ins.imm = imm0
-                       insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
-                       inss = append(inss, insADDI)
-                       break
-               }
-
-               // LUI $high, TMP
-               // ADDI $low, TMP, TMP
-               // <op> TMP, REG, TO
-               insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
-               insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
-               switch ins.as {
-               case AADDI:
-                       ins.as = AADD
-               case AANDI:
-                       ins.as = AAND
-               case AORI:
-                       ins.as = AOR
-               case AXORI:
-                       ins.as = AXOR
-               default:
-                       p.Ctxt.Diag("unsupported instruction %v for splitting", p)
-                       return nil
-               }
-               ins.rs2 = REG_TMP
-               inss = []*instruction{insLUI, insADDIW, ins}
+               inss = instructionsForOpImmediate(p, ins.as, p.Reg)
 
        case ASCW, ASCD, AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
                AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD: