diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s index 6de8b13709..a8b9e33db3 100644 --- a/src/cmd/asm/internal/asm/testdata/ppc64.s +++ b/src/cmd/asm/internal/asm/testdata/ppc64.s @@ -32,11 +32,17 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 MOVW $2147483649, R5 // 6405800060a50001 or 0600800038a00001 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 $-2147483647, R5 // 3ca0800060a50001 or 0603800038a00001 + // Hex constant 0xFFFFFFFE00000002 (load of constant on < power10, pli on >= power10 + MOVD $-8589934590, R5 // 3ca00000e8a50000 or 0602000038a00002 + + // TODO: These are preprocessed by the assembler into MOVD $const>>shift, R5; SLD $shift, R5. + // This only captures the MOVD. Should the SLD be appended to the encoding by the test? + // Hex constant 0x20004000000 + MOVD $2199090364416, R5 // 60058001 + // Hex constant 0xFFFFFE0004000000 + MOVD $-2198956146688, R5 // 38a08001 + MOVD 8(R3), R4 // e8830008 MOVD (R3)(R4), R5 // 7ca4182a MOVD (R3)(R0), R5 // 7ca0182a @@ -168,6 +174,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 ADD $-32767, R5, R4 // 38858001 ADD $-32768, R6 // 38c68000 ADD $-32768, R6, R5 // 38a68000 + // Hex constant 0xFFFFFFFE00000000 + ADD $-8589934592, R5 // 3fe0fffe63ff00007bff83e463ff00007cbf2a14 or 0602000038a50000 //TODO: this compiles to add r5,r6,r0. It should be addi r5,r6,0. // this is OK since r0 == $0, but the latter is preferred. diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index 7cd4dc2396..df0c36cde0 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -36,6 +36,7 @@ import ( "cmd/internal/sys" "internal/abi" "log" + "math/bits" ) func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { @@ -80,19 +81,34 @@ 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. + // 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 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 - p.From.Offset = 0 + + // 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)) + mask := 0xFFFF << shift + if val&int64(mask) == val || (val>>(shift+16) == -1 && (val>>shift)<>shift, Rto; SLD $shift, Rto + q := obj.Appendp(p, c.newprog) + q.As = ASLD + q.From.Type = obj.TYPE_CONST + q.From.Offset = int64(shift) + q.To = p.To + p.From.Offset >>= shift + p = q + } else { + // Load the constant from memory. + p.From.Type = obj.TYPE_MEM + p.From.Sym = ctxt.Int64Sym(p.From.Offset) + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } } } diff --git a/test/codegen/constants.go b/test/codegen/constants.go new file mode 100644 index 0000000000..756aeda5f7 --- /dev/null +++ b/test/codegen/constants.go @@ -0,0 +1,25 @@ +// asmcheck + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codegen + +func shifted16BitConstants(out [64]uint64) { + // ppc64x: "MOVD\t[$]8193,", "SLD\t[$]27," + out[0] = 0x0000010008000000 + // ppc64x: "MOVD\t[$]-32767", "SLD\t[$]26," + out[1] = 0xFFFFFE0004000000 + // ppc64x: "MOVD\t[$]-1", "SLD\t[$]48," + out[2] = 0xFFFF000000000000 + // ppc64x: "MOVD\t[$]65535", "SLD\t[$]44," + out[3] = 0x0FFFF00000000000 + + // ppc64x: "MOVD\t[$]i64.fffff00000000001[(]SB[)]" + out[4] = 0xFFFFF00000000001 + // ppc64x: "MOVD\t[$]i64.fffff80000000001[(]SB[)]" + out[5] = 0xFFFFF80000000001 + // ppc64x: "MOVD\t[$]i64.0ffff80000000000[(]SB[)]" + out[6] = 0x0FFFF80000000000 +}