aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal')
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go39
-rw-r--r--src/cmd/internal/obj/arm64/asm_arm64_test.go13
-rw-r--r--src/cmd/internal/obj/arm64/asm_arm64_test.s8
3 files changed, 59 insertions, 1 deletions
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 7e7f028bfb..ccf8eda495 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -38,6 +38,7 @@ import (
"fmt"
"log"
"math"
+ "math/bits"
"slices"
"strings"
)
@@ -1976,7 +1977,18 @@ func (c *ctxt7) con64class(a *obj.Addr) int {
return C_MOVCON
} else if zeroCount == 2 || negCount == 2 {
return C_MOVCON2
- } else if zeroCount == 1 || negCount == 1 {
+ }
+ // See omovlconst for description of this loop.
+ for i := 0; i < 4; i++ {
+ mask := uint64(0xffff) << (i * 16)
+ for period := 2; period <= 32; period *= 2 {
+ x := uint64(a.Offset)&^mask | bits.RotateLeft64(uint64(a.Offset), max(period, 16))&mask
+ if isbitcon(x) {
+ return C_MOVCON2
+ }
+ }
+ }
+ if zeroCount == 1 || negCount == 1 {
return C_MOVCON3
} else {
return C_VCON
@@ -7555,6 +7567,31 @@ func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uin
}
}
return 2
+ }
+
+ // Look for a two instruction pair, a bit pattern encodeable
+ // as a bitcon immediate plus a fixup MOVK instruction.
+ // Constants like this often occur from strength reduction of divides.
+ for i = 0; i < 4; i++ {
+ mask := uint64(0xffff) << (i * 16)
+ for period := 2; period <= 32; period *= 2 { // TODO: handle period==64 somehow?
+ // Copy in bits from outside of the masked region
+ x := uint64(d)&^mask | bits.RotateLeft64(uint64(d), max(period, 16))&mask
+ if isbitcon(x) {
+ // ORR $c1, ZR, rt
+ os[0] = c.opirr(p, AORR)
+ os[0] |= bitconEncode(x, 64) | uint32(REGZERO&31)<<5 | uint32(rt&31)
+ // MOVK $c2<<(i*16), rt
+ os[1] = c.opirr(p, AMOVK)
+ os[1] |= MOVCONST(d, i, rt)
+ return 2
+ }
+ }
+ }
+ // TODO: other fixups, like ADD or SUB?
+ // TODO: 3-instruction variant, instead of the full MOVD+3*MOVK version below?
+
+ switch {
case zeroCount == 1:
// one MOVZ and two MOVKs
diff --git a/src/cmd/internal/obj/arm64/asm_arm64_test.go b/src/cmd/internal/obj/arm64/asm_arm64_test.go
index 83d137a084..b83db60b40 100644
--- a/src/cmd/internal/obj/arm64/asm_arm64_test.go
+++ b/src/cmd/internal/obj/arm64/asm_arm64_test.go
@@ -38,3 +38,16 @@ func TestMOVK(t *testing.T) {
t.Errorf("Got %x want %x\n", x, want)
}
}
+
+func testCombined() (a uint64, b uint64)
+func TestCombined(t *testing.T) {
+ got1, got2 := testCombined()
+ want1 := uint64(0xaaaaaaaaaaaaaaab)
+ want2 := uint64(0x0ff019940ff00ff0)
+ if got1 != want1 {
+ t.Errorf("First result, got %x want %x", got1, want1)
+ }
+ if got2 != want2 {
+ t.Errorf("First result, got %x want %x", got2, want2)
+ }
+}
diff --git a/src/cmd/internal/obj/arm64/asm_arm64_test.s b/src/cmd/internal/obj/arm64/asm_arm64_test.s
index e3fda57775..65d80d1380 100644
--- a/src/cmd/internal/obj/arm64/asm_arm64_test.s
+++ b/src/cmd/internal/obj/arm64/asm_arm64_test.s
@@ -37,3 +37,11 @@ TEXT ·testmovk(SB), NOSPLIT, $0-8
MOVK $(40000<<48), R0
MOVD R0, ret+0(FP)
RET
+
+// testCombined() (uint64, uint64)
+TEXT ·testCombined(SB), NOSPLIT, $0-16
+ MOVD $0xaaaaaaaaaaaaaaab, R0
+ MOVD $0x0ff019940ff00ff0, R1
+ MOVD R0, a+0(FP)
+ MOVD R1, b+8(FP)
+ RET