aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj
diff options
context:
space:
mode:
authorPaul E. Murphy <murp@ibm.com>2024-02-16 13:29:16 -0600
committerPaul Murphy <murp@ibm.com>2024-03-13 13:58:44 +0000
commit6e5398bad16aba15db365b72cb70d1177330b603 (patch)
treeea00cfdf9c6f9d96be1065237d4b25c8d01a2823 /src/cmd/internal/obj
parenta46ecdca36b2359e7496c6d694703a9a9706d760 (diff)
downloadgo-6e5398bad16aba15db365b72cb70d1177330b603.tar.xz
cmd/asm,cmd/compile: generate less instructions for most 32 bit constant adds on ppc64x
For GOPPC64 < 10 targets, most large 32 bit constants (those exceeding int16 capacity) can be added using two instructions instead of 3. This cannot be done for values greater than 0x7FFF7FFF, so this must be done during asm preprocessing as the optab matching rules cannot differentiate this special case. Likewise, constants 0x8000 <= x < 0x10000 are not converted. The assembler currently generates 2 instructions sequences for these constants. Change-Id: I1ccc839c6c28fc32f15d286b2e52e2d22a2a06d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/568116 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Paul Murphy <murp@ibm.com> Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/cmd/internal/obj')
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go42
1 files changed, 37 insertions, 5 deletions
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index a3d392d62c..ab7e0f6a77 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -35,6 +35,7 @@ import (
"cmd/internal/src"
"cmd/internal/sys"
"internal/abi"
+ "internal/buildcfg"
"log"
"math/bits"
)
@@ -203,17 +204,48 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
case ASUB:
- if p.From.Type == obj.TYPE_CONST {
- p.From.Offset = -p.From.Offset
- p.As = AADD
+ if p.From.Type != obj.TYPE_CONST {
+ break
}
+ // Rewrite SUB $const,... into ADD $-const,...
+ p.From.Offset = -p.From.Offset
+ p.As = AADD
+ // This is now an ADD opcode, try simplifying it below.
+ fallthrough
// 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 {
+ // Don't rewrite if this is not adding a constant value, or is not an int32
+ if p.From.Type != obj.TYPE_CONST || p.From.Offset == 0 || int64(int32(p.From.Offset)) != p.From.Offset {
+ break
+ }
+ if p.From.Offset&0xFFFF == 0 {
+ // The constant can be added using ADDIS
p.As = AADDIS
p.From.Offset >>= 16
+ } else if buildcfg.GOPPC64 >= 10 {
+ // Let the assembler generate paddi for large constants.
+ break
+ } else if (p.From.Offset < -0x8000 && int64(int32(p.From.Offset)) == p.From.Offset) || (p.From.Offset > 0xFFFF && p.From.Offset < 0x7FFF8000) {
+ // For a constant x, 0xFFFF (UINT16_MAX) < x < 0x7FFF8000 or -0x80000000 (INT32_MIN) <= x < -0x8000 (INT16_MIN)
+ // This is not done for 0x7FFF < x < 0x10000; the assembler will generate a slightly faster instruction sequence.
+ //
+ // The constant x can be rewritten as ADDIS + ADD as follows:
+ // ADDIS $x>>16 + (x>>15)&1, rX, rY
+ // ADD $int64(int16(x)), rY, rY
+ // The range is slightly asymmetric as 0x7FFF8000 and above overflow the sign bit, whereas for
+ // negative values, this would happen with constant values between -1 and -32768 which can
+ // assemble into a single addi.
+ is := p.From.Offset>>16 + (p.From.Offset>>15)&1
+ i := int64(int16(p.From.Offset))
+ p.As = AADDIS
+ p.From.Offset = is
+ q := obj.Appendp(p, c.newprog)
+ q.As = AADD
+ q.From.SetConst(i)
+ q.Reg = p.To.Reg
+ q.To = p.To
+ p = q
}
case AOR:
if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {