]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/internal/asm/ppc64: support 34b ADD/MOVD $const, Rx
authorPaul E. Murphy <murp@ibm.com>
Tue, 12 Sep 2023 21:06:45 +0000 (16:06 -0500)
committerPaul Murphy <murp@ibm.com>
Tue, 3 Oct 2023 20:22:46 +0000 (20:22 +0000)
For constant signed values which require 34b to represent,
the assembler will generate a pli instruction on
linux/power10/PPC64 instead of loading a constant.

Similarly, ADD is extended to support 34b signed constants.
On linux/power10/PPC64, this generates a paddi instruction.
For assembler consistency, a second form is added if paddi
cannot be used. The second form is provided for assembly
writers.

Change-Id: I98144306af766b02fbbe36b72856a23cdf51d247
Reviewed-on: https://go-review.googlesource.com/c/go/+/528317
TryBot-Result: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Eli Bendersky <eliben@google.com>
Run-TryBot: Paul Murphy <murp@ibm.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
src/cmd/asm/internal/asm/testdata/ppc64.s
src/cmd/internal/obj/ppc64/asm9.go
src/cmd/internal/obj/ppc64/obj9.go

index 2bf04971edbf1d76ef731417109e24cd382a9a45..6de8b137091ef46ce64ac5f2e3144f88e8e4f13a 100644 (file)
@@ -33,6 +33,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        MOVD $2147483649, R5            // 6405800060a50001 or 0600800038a00001
        // Hex constant 0xFFFFFFFF80000001
        MOVD $-2147483647, R5           // 3ca0800060a50001 or 0603800038a00001
+       // Hex constant 0xFFFFFFFE00000000 (load of constant on < power10, pli on >= power10
+       MOVD $-8589934592, R5           // 3ca00000e8a50000 or 0602000038a00000
+       // Hex constant 0xFFFFFFFE00000000
+       ADD $-8589934592, R5            // 3fe0fffe63ff00007bff83e463ff00007cbf2a14 or 0602000038a50000
        MOVD 8(R3), R4                  // e8830008
        MOVD (R3)(R4), R5               // 7ca4182a
        MOVD (R3)(R0), R5               // 7ca0182a
index 4ce506cbf9a8824acdb0ab8672cf7cbbf2811db9..65b8c583d91927ce980b622cc3f5d40d46680622 100644 (file)
@@ -545,7 +545,7 @@ type PrefixableOptab struct {
 //
 // This requires an ISA 3.1 compatible cpu (e.g Power10), and when linking externally an ELFv2 1.5 compliant.
 var prefixableOptab = []PrefixableOptab{
-       {Optab: Optab{as: AMOVD, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, minGOPPC64: 10, pfxsize: 8},
+       {Optab: Optab{as: AMOVD, a1: C_S34CON, a6: C_REG, type_: 19, size: 8}, minGOPPC64: 10, pfxsize: 8},
        {Optab: Optab{as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, minGOPPC64: 10, pfxsize: 8},
        {Optab: Optab{as: AMOVD, a1: C_TLS_LE, a6: C_REG, type_: 79, size: 8}, minGOPPC64: 10, pfxsize: 8},
        {Optab: Optab{as: AMOVD, a1: C_TLS_IE, a6: C_REG, type_: 80, size: 12}, minGOPPC64: 10, pfxsize: 12},
@@ -578,6 +578,8 @@ var prefixableOptab = []PrefixableOptab{
 
        {Optab: Optab{as: AADD, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 22, size: 12}, minGOPPC64: 10, pfxsize: 8},
        {Optab: Optab{as: AADD, a1: C_LCON, a6: C_REG, type_: 22, size: 12}, minGOPPC64: 10, pfxsize: 8},
+       {Optab: Optab{as: AADD, a1: C_S34CON, a2: C_REG, a6: C_REG, type_: 22, size: 20}, minGOPPC64: 10, pfxsize: 8},
+       {Optab: Optab{as: AADD, a1: C_S34CON, a6: C_REG, type_: 22, size: 20}, minGOPPC64: 10, pfxsize: 8},
 }
 
 var oprange [ALAST & obj.AMask][]Optab
@@ -2978,7 +2980,7 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
                        o1 = AOP_IRR(c.opirr(AADDIS), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
                }
 
-       case 22: /* add $lcon/$andcon,r1,r2 ==> oris+ori+add/ori+add */
+       case 22: /* add $lcon/$andcon,r1,r2 ==> oris+ori+add/ori+add, add $s34con,r1 ==> addis+ori+slw+ori+add */
                if p.To.Reg == REGTMP || p.Reg == REGTMP {
                        c.ctxt.Diag("can't synthesize large constant\n%v", p)
                }
@@ -2990,19 +2992,23 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
                if p.From.Sym != nil {
                        c.ctxt.Diag("%v is not supported", p)
                }
-               // If operand is ANDCON, generate 2 instructions using
-               // ORI for unsigned value; with LCON 3 instructions.
-               if o.size == 8 {
-                       o1 = LOP_IRR(OP_ORI, REGTMP, REGZERO, uint32(int32(d)))
-                       o2 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
-               } else {
-                       o1 = loadu32(REGTMP, d)
-                       o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
-                       o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
-               }
-
                if o.ispfx {
                        o1, o2 = pfxadd(int16(p.To.Reg), int16(r), PFX_R_ABS, d)
+               } else if o.size == 8 {
+                       o1 = LOP_IRR(OP_ORI, REGTMP, REGZERO, uint32(int32(d)))          // tmp = uint16(d)
+                       o2 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r)) // to = tmp + from
+               } else if o.size == 12 {
+                       // Note, o1 is ADDIS if d is negative, ORIS otherwise.
+                       o1 = loadu32(REGTMP, d)                                          // tmp = d & 0xFFFF0000
+                       o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))           // tmp |= d & 0xFFFF
+                       o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r)) // to = from + tmp
+               } else {
+                       // For backwards compatibility with GOPPC64 < 10, generate 34b constants in register.
+                       o1 = LOP_IRR(OP_ADDIS, REGZERO, REGTMP, uint32(d>>32))  // tmp = sign_extend((d>>32)&0xFFFF0000)
+                       o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(d>>16))     // tmp |= (d>>16)&0xFFFF
+                       o3 = AOP_RLDIC(OP_RLDICR, REGTMP, REGTMP, 16, 63-16)    // tmp <<= 16
+                       o4 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(uint16(d))) // tmp |= d&0xFFFF
+                       o5 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
                }
 
        case 23: /* and $lcon/$addcon,r1,r2 ==> oris+ori+and/addi+and */
index da95e65079c4c7bc95eba9574221e00001496002..7cd4dc2396d0750ea50e36e760eae1060387763f 100644 (file)
@@ -81,10 +81,14 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 
        case AMOVD:
                // 32b constants (signed and unsigned) can be generated via 1 or 2 instructions.
-               // All others must be placed in memory and loaded.
                isS32 := int64(int32(p.From.Offset)) == p.From.Offset
                isU32 := uint64(uint32(p.From.Offset)) == uint64(p.From.Offset)
-               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && !isS32 && !isU32 {
+
+               // If prefixed instructions are supported, a 34b signed constant can be generated by one pli instruction.
+               isS34 := pfxEnabled && (p.From.Offset<<30)>>30 == p.From.Offset
+
+               // If the constant cannot be generated with 2 or less instructions, it must be placed in memory and loaded.
+               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && !isS32 && !isU32 && !isS34 {
                        p.From.Type = obj.TYPE_MEM
                        p.From.Sym = ctxt.Int64Sym(p.From.Offset)
                        p.From.Name = obj.NAME_EXTERN