]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/internal/obj/ppc64/obj9.go
cmd/internal/obj/ppc64: remove C_UCON optab matching class
[gostls13.git] / src / cmd / internal / obj / ppc64 / obj9.go
index ab397892c2d89f86ff890d38403452dbf846dbb9..a3d392d62c263e7c1b4e2ba617485746ba1272a0 100644 (file)
@@ -113,15 +113,48 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                        }
                }
 
+       case AMOVW, AMOVWZ:
+               // Note, for backwards compatibility, MOVW $const, Rx and MOVWZ $const, Rx are identical.
+               if p.From.Type == obj.TYPE_CONST && p.From.Offset != 0 && p.From.Offset&0xFFFF == 0 {
+                       // This is a constant shifted 16 bits to the left, convert it to ADDIS/ORIS $const,...
+                       p.As = AADDIS
+                       // Use ORIS for large constants which should not be sign extended.
+                       if p.From.Offset >= 0x80000000 {
+                               p.As = AORIS
+                       }
+                       p.Reg = REG_R0
+                       p.From.Offset >>= 16
+               }
+
        case AMOVD:
+               // Skip this opcode if it is not a constant load.
+               if p.From.Type != obj.TYPE_CONST || p.From.Name != obj.NAME_NONE || p.From.Reg != 0 {
+                       break
+               }
+
                // 32b constants (signed and unsigned) can be generated via 1 or 2 instructions. They can be assembled directly.
                isS32 := int64(int32(p.From.Offset)) == p.From.Offset
                isU32 := uint64(uint32(p.From.Offset)) == uint64(p.From.Offset)
-
                // 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 p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && !isS32 && !isU32 && !isS34 {
 
+               // Try converting MOVD $const,Rx into ADDIS/ORIS $s32>>16,R0,Rx
+               switch {
+               case isS32 && p.From.Offset&0xFFFF == 0 && p.From.Offset != 0:
+                       p.As = AADDIS
+                       p.From.Offset >>= 16
+                       p.Reg = REG_R0
+
+               case isU32 && p.From.Offset&0xFFFF == 0 && p.From.Offset != 0:
+                       p.As = AORIS
+                       p.From.Offset >>= 16
+                       p.Reg = REG_R0
+
+               case isS32 || isU32 || isS34:
+                       // The assembler can generate this opcode in 1 (on Power10) or 2 opcodes.
+
+               // Otherwise, see if the large constant can be generated with 2 instructions. If not, load it from memory.
+               default:
                        // Is this a shifted 16b constant? If so, rewrite it to avoid a creating and loading a constant.
                        val := p.From.Offset
                        shift := bits.TrailingZeros64(uint64(val))
@@ -134,8 +167,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                                q.To = p.To
                                p.From.Offset >>= shift
                                p = q
-                               // Is this constant a mask value? If so, generate MOVD $-1, Rto; RLDIC Rto, ^me, mb, Rto
                        } else if isPPC64DoublewordRotateMask(val) {
+                               // This constant is a mask value, generate MOVD $-1, Rto; RLDIC Rto, ^me, mb, Rto
                                mb, me := encodePPC64RLDCMask(val)
                                q := obj.Appendp(p, c.newprog)
                                q.As = ARLDC
@@ -175,6 +208,29 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                        p.As = AADD
                }
 
+       // Rewrite ADD/OR/XOR/ANDCC $const,... forms into ADDIS/ORIS/XORIS/ANDISCC
+       case AADD:
+               // AADD can encode signed 34b values, ensure it is a valid signed 32b integer too.
+               if p.From.Type == obj.TYPE_CONST && p.From.Offset&0xFFFF == 0 && int64(int32(p.From.Offset)) == p.From.Offset && p.From.Offset != 0 {
+                       p.As = AADDIS
+                       p.From.Offset >>= 16
+               }
+       case AOR:
+               if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
+                       p.As = AORIS
+                       p.From.Offset >>= 16
+               }
+       case AXOR:
+               if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
+                       p.As = AXORIS
+                       p.From.Offset >>= 16
+               }
+       case AANDCC:
+               if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
+                       p.As = AANDISCC
+                       p.From.Offset >>= 16
+               }
+
        // To maintain backwards compatibility, we accept some 4 argument usage of
        // several opcodes which was likely not intended, but did work. These are not
        // added to optab to avoid the chance this behavior might be used with newer