aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2016-08-03 11:47:40 -0400
committerCherry Zhang <cherryyz@google.com>2016-08-10 20:33:11 +0000
commit748aa84424418fb71c2528e7340df0ad6075b265 (patch)
tree906d259dcbfb236800db4df9a1b99ae02276c17d
parentc069bc49963bd5c2c152fe600fdcb9a2b7b58f76 (diff)
downloadgo-748aa84424418fb71c2528e7340df0ad6075b265.tar.gz
go-748aa84424418fb71c2528e7340df0ad6075b265.zip
[dev.ssa] cmd/internal/obj/arm64: fix encoding constant into some instructions
When a constant can be encoded in a logical instruction (BITCON), do it this way instead of using the constant pool. The BITCON testing code runs faster than table lookup (using map): (on AMD64 machine, with pseudo random input) BenchmarkIsBitcon-4 300000000 4.04 ns/op BenchmarkTable-4 50000000 27.3 ns/op The equivalent C code of BITCON testing is formally verified with model checker CBMC against linear search of the lookup table. Also handle cases when a constant can be encoded in a MOV instruction. In this case, materializa the constant into REGTMP without using the constant pool. When constants need to be added to the constant pool, make sure to check whether it fits in 32-bit. If not, store 64-bit. Both legacy and SSA compiler backends are happy with this. Fixes #16226. Change-Id: I883e3069dee093a1cdc40853c42221a198a152b0 Reviewed-on: https://go-review.googlesource.com/26631 Run-TryBot: Cherry Zhang <cherryyz@google.com> Reviewed-by: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
-rw-r--r--src/cmd/internal/obj/arm64/a.out.go1
-rw-r--r--src/cmd/internal/obj/arm64/anames7.go1
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go358
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go30
4 files changed, 294 insertions, 96 deletions
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index ab05894950..ad52be66b8 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -274,6 +274,7 @@ const (
C_ADDCON // 12-bit unsigned, shifted left by 0 or 12
C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
C_BITCON // bitfield and logical immediate masks
+ C_ABCON0 // could be C_ADDCON0 or C_BITCON
C_ABCON // could be C_ADDCON or C_BITCON
C_MBCON // could be C_MOVCON or C_BITCON
C_LCON // 32-bit constant
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index eb348d4850..d55b34f9ae 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -20,6 +20,7 @@ var cnames7 = []string{
"ADDCON",
"MOVCON",
"BITCON",
+ "ABCON0",
"ABCON",
"MBCON",
"LCON",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 28bebaa3f7..fbf0378591 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -161,10 +161,12 @@ var optab = []Optab{
{AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
{AADD, C_ADDCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
{ACMP, C_ADDCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
- // TODO: these don't work properly.
- // {AADD, C_MBCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
- // {AADD, C_MBCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
- // {ACMP, C_MBCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
+ {AADD, C_MOVCON, C_RSP, C_RSP, 62, 8, 0, 0, 0},
+ {AADD, C_MOVCON, C_NONE, C_RSP, 62, 8, 0, 0, 0},
+ {ACMP, C_MOVCON, C_RSP, C_NONE, 62, 8, 0, 0, 0},
+ {AADD, C_BITCON, C_RSP, C_RSP, 62, 8, 0, 0, 0},
+ {AADD, C_BITCON, C_NONE, C_RSP, 62, 8, 0, 0, 0},
+ {ACMP, C_BITCON, C_RSP, C_NONE, 62, 8, 0, 0, 0},
{AADD, C_VCON, C_RSP, C_RSP, 13, 8, 0, LFROM, 0},
{AADD, C_VCON, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{ACMP, C_VCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
@@ -188,11 +190,14 @@ var optab = []Optab{
{AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
{ABIC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
{ABIC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- // TODO: these don't work properly.
- // {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
- // {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
- // {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
- // {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+ {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_MOVCON, C_REG, C_REG, 62, 8, 0, 0, 0},
+ {AAND, C_MOVCON, C_NONE, C_REG, 62, 8, 0, 0, 0},
+ {ABIC, C_MOVCON, C_REG, C_REG, 62, 8, 0, 0, 0},
+ {ABIC, C_MOVCON, C_NONE, C_REG, 62, 8, 0, 0, 0},
{AAND, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
{AAND, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{ABIC, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
@@ -216,8 +221,8 @@ var optab = []Optab{
// TODO: these don't work properly.
// { AMOVW, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0},
// { AMOVD, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0},
- // { AMOVW, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0},
- // { AMOVD, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0},
+ {AMOVW, C_BITCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
+ {AMOVD, C_BITCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVK, C_VCON, C_NONE, C_REG, 33, 4, 0, 0, 0},
{AMOVD, C_AACON, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
@@ -715,15 +720,18 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) {
*/
func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
c := aclass(ctxt, a)
+ lit := ctxt.Instoffset
t := *ctxt.NewProg()
t.As = AWORD
sz := 4
- // MOVW foo(SB), R is actually
- // MOV addr, REGTEMP
- // MOVW REGTEMP, R
+ // MOVD foo(SB), R is actually
+ // MOVD addr, REGTMP
+ // MOVD REGTMP, R
// where addr is the address of the DWORD containing the address of foo.
- if p.As == AMOVD || c == C_ADDR || c == C_VCON {
+ if p.As == AMOVD || c == C_ADDR || c == C_VCON || int64(lit) != int64(int32(lit)) || uint64(lit) != uint64(uint32(lit)) {
+ // conservative: don't know if we want signed or unsigned extension.
+ // in case of ambiguity, store 64-bit
t.As = ADWORD
sz = 8
}
@@ -740,29 +748,12 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
t.To.Type = a.Type
t.To.Name = a.Name
- /* This is here to work around a bug where we generate negative
- operands that match C_MOVCON, but we use them with
- instructions that only accept unsigned immediates. This
- will cause oplook to return a variant of the instruction
- that loads the negative constant from memory, rather than
- using the immediate form. Because of that load, we get here,
- so we need to know what to do with C_MOVCON.
-
- The correct fix is to use the "negation" instruction variant,
- e.g. CMN $1, R instead of CMP $-1, R, or SUB $1, R instead
- of ADD $-1, R. */
- case C_MOVCON,
-
- /* This is here because MOV uint12<<12, R is disabled in optab.
- Because of this, we need to load the constant from memory. */
- C_ADDCON,
-
- /* These are here because they are disabled in optab.
- Because of this, we need to load the constant from memory. */
- C_BITCON,
- C_ABCON,
- C_MBCON,
- C_PSAUTO,
+ /* This is here because MOV uint12<<12, R is disabled in optab.
+ Because of this, we need to load the constant from memory. */
+ case C_ADDCON:
+ fallthrough
+
+ case C_PSAUTO,
C_PPAUTO,
C_UAUTO4K,
C_UAUTO8K,
@@ -790,7 +781,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
}
t.To.Type = obj.TYPE_CONST
- t.To.Offset = ctxt.Instoffset
+ t.To.Offset = lit
break
}
@@ -844,11 +835,137 @@ func isaddcon(v int64) bool {
return v <= 0xFFF
}
-func isbitcon(v uint64) bool {
- /* fancy bimm32 or bimm64? */
- // TODO(aram):
- return false
- // return findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil
+// isbitcon returns whether a constant can be encoded into a logical instruction.
+// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64,
+// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones.
+// special cases: 0 and -1 are not bitcon.
+// this function needs to run against virtually all the constants, so it needs to be fast.
+// for this reason, bitcon testing and bitcon encoding are separate functions.
+func isbitcon(x uint64) bool {
+ if x == 1<<64-1 || x == 0 {
+ return false
+ }
+ // determine the period and sign-extend a unit to 64 bits
+ switch {
+ case x != x>>32|x<<32:
+ // period is 64
+ // nothing to do
+ case x != x>>16|x<<48:
+ // period is 32
+ x = uint64(int64(int32(x)))
+ case x != x>>8|x<<56:
+ // period is 16
+ x = uint64(int64(int16(x)))
+ case x != x>>4|x<<60:
+ // period is 8
+ x = uint64(int64(int8(x)))
+ default:
+ // period is 4 or 2, always true
+ // 0001, 0010, 0100, 1000 -- 0001 rotate
+ // 0011, 0110, 1100, 1001 -- 0011 rotate
+ // 0111, 1011, 1101, 1110 -- 0111 rotate
+ // 0101, 1010 -- 01 rotate, repeat
+ return true
+ }
+ return sequenceOfOnes(x) || sequenceOfOnes(^x)
+}
+
+// sequenceOfOnes tests whether a constant is a sequence of ones in binary, with leading and trailing zeros
+func sequenceOfOnes(x uint64) bool {
+ y := x & -x // lowest set bit of x. x is good iff x+y is a power of 2
+ y += x
+ return (y-1)&y == 0
+}
+
+// bitconEncode returns the encoding of a bitcon used in logical instructions
+// x is known to be a bitcon
+// a bitcon is a sequence of n ones at low bits (i.e. 1<<n-1), right rotated
+// by R bits, and repeated with period of 64, 32, 16, 8, 4, or 2.
+// it is encoded in logical instructions with 3 bitfields
+// N (1 bit) : R (6 bits) : S (6 bits), where
+// N=1 -- period=64
+// N=0, S=0xxxxx -- period=32
+// N=0, S=10xxxx -- period=16
+// N=0, S=110xxx -- period=8
+// N=0, S=1110xx -- period=4
+// N=0, S=11110x -- period=2
+// R is the shift amount, low bits of S = n-1
+func bitconEncode(x uint64, mode int) uint32 {
+ var period uint32
+ // determine the period and sign-extend a unit to 64 bits
+ switch {
+ case x != x>>32|x<<32:
+ period = 64
+ case x != x>>16|x<<48:
+ period = 32
+ x = uint64(int64(int32(x)))
+ case x != x>>8|x<<56:
+ period = 16
+ x = uint64(int64(int16(x)))
+ case x != x>>4|x<<60:
+ period = 8
+ x = uint64(int64(int8(x)))
+ case x != x>>2|x<<62:
+ period = 4
+ x = uint64(int64(x<<60) >> 60)
+ default:
+ period = 2
+ x = uint64(int64(x<<62) >> 62)
+ }
+ neg := false
+ if int64(x) < 0 {
+ x = ^x
+ neg = true
+ }
+ y := x & -x // lowest set bit of x.
+ s := log2(y)
+ n := log2(x+y) - s // x (or ^x) is a sequence of n ones left shifted by s bits
+ if neg {
+ // ^x is a sequence of n ones left shifted by s bits
+ // adjust n, s for x
+ s = n + s
+ n = period - n
+ }
+
+ N := uint32(0)
+ if mode == 64 && period == 64 {
+ N = 1
+ }
+ R := (period - s) & (period - 1) & uint32(mode-1) // shift amount of right rotate
+ S := (n - 1) | 63&^(period<<1-1) // low bits = #ones - 1, high bits encodes period
+ return N<<22 | R<<16 | S<<10
+}
+
+func log2(x uint64) uint32 {
+ if x == 0 {
+ panic("log2 of 0")
+ }
+ n := uint32(0)
+ if x >= 1<<32 {
+ x >>= 32
+ n += 32
+ }
+ if x >= 1<<16 {
+ x >>= 16
+ n += 16
+ }
+ if x >= 1<<8 {
+ x >>= 8
+ n += 8
+ }
+ if x >= 1<<4 {
+ x >>= 4
+ n += 4
+ }
+ if x >= 1<<2 {
+ x >>= 2
+ n += 2
+ }
+ if x >= 1<<1 {
+ x >>= 1
+ n += 1
+ }
+ return n
}
func autoclass(l int64) int {
@@ -1019,6 +1136,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
}
if isaddcon(v) {
if v <= 0xFFF {
+ if isbitcon(uint64(v)) {
+ return C_ABCON0
+ }
return C_ADDCON0
}
if isbitcon(uint64(v)) {
@@ -1085,6 +1205,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_GOK
}
+func oclass(a *obj.Addr) int {
+ return int(a.Class) - 1
+}
+
func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a1 := int(p.Optab)
if a1 != 0 {
@@ -1151,17 +1275,17 @@ func cmp(a int, b int) bool {
}
case C_ADDCON0:
- if b == C_ZCON {
+ if b == C_ZCON || b == C_ABCON0 {
return true
}
case C_ADDCON:
- if b == C_ZCON || b == C_ADDCON0 || b == C_ABCON {
+ if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON {
return true
}
case C_BITCON:
- if b == C_ABCON || b == C_MBCON {
+ if b == C_ABCON0 || b == C_ABCON || b == C_MBCON {
return true
}
@@ -1171,7 +1295,7 @@ func cmp(a int, b int) bool {
}
case C_LCON:
- if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_MBCON || b == C_MOVCON {
+ if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON {
return true
}
@@ -2306,34 +2430,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o2 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
case 32: /* mov $con, R -> movz/movn */
- r := 32
-
- if p.As == AMOVD {
- r = 64
- }
- d := p.From.Offset
- s := movcon(d)
- if s < 0 || s >= r {
- d = ^d
- s = movcon(d)
- if s < 0 || s >= r {
- ctxt.Diag("impossible move wide: %#x\n%v", uint64(p.From.Offset), p)
- }
- if p.As == AMOVD {
- o1 = opirr(ctxt, AMOVN)
- } else {
- o1 = opirr(ctxt, AMOVNW)
- }
- } else {
- if p.As == AMOVD {
- o1 = opirr(ctxt, AMOVZ)
- } else {
- o1 = opirr(ctxt, AMOVZW)
- }
- }
-
- rt := int(p.To.Reg)
- o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+ o1 = omovconst(ctxt, p.As, p, &p.From, int(p.To.Reg))
case 33: /* movk $uimm16 << pos */
o1 = opirr(ctxt, p.As)
@@ -2601,8 +2698,26 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 |= uint32((p.From.Offset & 0x7F) << 5)
- case 53: /* and/or/eor/bic/... $bimmN, Rn, Rd -> op (N,r,s), Rn, Rd */
- ctxt.Diag("bitmask immediate not implemented\n%v", p)
+ case 53: /* and/or/eor/bic/... $bitcon, Rn, Rd */
+ a := p.As
+ rt := int(p.To.Reg)
+ r := int(p.Reg)
+ if r == 0 {
+ r = rt
+ }
+ mode := 64
+ v := uint64(p.From.Offset)
+ switch p.As {
+ case AANDW, AORRW, AEORW, AANDSW:
+ mode = 32
+ case ABIC, AORN, AEON, ABICS:
+ v = ^v
+ case ABICW, AORNW, AEONW, ABICSW:
+ v = ^v
+ mode = 32
+ }
+ o1 = opirr(ctxt, a)
+ o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31)
case 54: /* floating point arith */
o1 = oprrr(ctxt, p.As)
@@ -2694,6 +2809,31 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = ADR(0, uint32(d), uint32(p.To.Reg))
+ case 62: /* op $movcon, [R], R -> mov $movcon, REGTMP + op REGTMP, [R], R */
+ if p.Reg == REGTMP {
+ ctxt.Diag("cannot use REGTMP as source: %v\n", p)
+ }
+ o1 = omovconst(ctxt, AMOVD, p, &p.From, REGTMP)
+
+ rt := int(p.To.Reg)
+ if p.To.Type == obj.TYPE_NONE {
+ rt = REGZERO
+ }
+ r := int(p.Reg)
+ if r == 0 {
+ r = rt
+ }
+ if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
+ o2 = opxrrr(ctxt, p.As)
+ o2 |= REGTMP & 31 << 16
+ o2 |= LSL0_64
+ } else {
+ o2 = oprrr(ctxt, p.As)
+ o2 |= REGTMP & 31 << 16 /* shift is 0 */
+ }
+ o2 |= uint32(r&31) << 5
+ o2 |= uint32(rt & 31)
+
/* reloc ops */
case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
o1 = ADR(1, 0, REGTMP)
@@ -3374,28 +3514,28 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
return 1<<31 | 0x10<<24
/* op $bimm, Rn, Rd */
- case AAND:
+ case AAND, ABIC:
return S64 | 0<<29 | 0x24<<23
- case AANDW:
+ case AANDW, ABICW:
return S32 | 0<<29 | 0x24<<23 | 0<<22
- case AORR:
+ case AORR, AORN:
return S64 | 1<<29 | 0x24<<23
- case AORRW:
+ case AORRW, AORNW:
return S32 | 1<<29 | 0x24<<23 | 0<<22
- case AEOR:
+ case AEOR, AEON:
return S64 | 2<<29 | 0x24<<23
- case AEORW:
+ case AEORW, AEONW:
return S32 | 2<<29 | 0x24<<23 | 0<<22
- case AANDS:
+ case AANDS, ABICS:
return S64 | 3<<29 | 0x24<<23
- case AANDSW:
+ case AANDSW, ABICSW:
return S32 | 3<<29 | 0x24<<23 | 0<<22
case AASR:
@@ -4100,6 +4240,52 @@ func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32
return uint32(o1)
}
+// load a constant (MOVCON or BITCON) in a into rt
+func omovconst(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
+ if c := oclass(a); c == C_BITCON || c == C_ABCON || c == C_ABCON0 {
+ // or $bitcon, REGZERO, rt
+ mode := 64
+ var as1 obj.As
+ switch as {
+ case AMOVW:
+ as1 = AORRW
+ mode = 32
+ case AMOVD:
+ as1 = AORR
+ }
+ o1 = opirr(ctxt, as1)
+ o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31)
+ return o1
+ }
+
+ r := 32
+ if as == AMOVD {
+ r = 64
+ }
+ d := a.Offset
+ s := movcon(d)
+ if s < 0 || s >= r {
+ d = ^d
+ s = movcon(d)
+ if s < 0 || s >= r {
+ ctxt.Diag("impossible move wide: %#x\n%v", uint64(a.Offset), p)
+ }
+ if as == AMOVD {
+ o1 = opirr(ctxt, AMOVN)
+ } else {
+ o1 = opirr(ctxt, AMOVNW)
+ }
+ } else {
+ if as == AMOVD {
+ o1 = opirr(ctxt, AMOVZ)
+ } else {
+ o1 = opirr(ctxt, AMOVZW)
+ }
+ }
+ o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+ return o1
+}
+
func opbfm(ctxt *obj.Link, a obj.As, r int, s int, rf int, rt int) uint32 {
var c uint32
o := opirr(ctxt, a)
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index ffa1b416d6..3f606dd697 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -279,20 +279,30 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
// Rewrite negative immediates as positive immediates with
// complementary instruction.
switch p.As {
- case AADD,
- AADDW,
- ASUB,
- ASUBW,
- ACMP,
- ACMPW,
- ACMN,
- ACMNW:
- if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 {
+ case AADD, ASUB, ACMP, ACMN:
+ if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
p.From.Offset = -p.From.Offset
p.As = complements[p.As]
}
+ case AADDW, ASUBW, ACMPW, ACMNW:
+ if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
+ p.From.Offset = -p.From.Offset
+ p.As = complements[p.As]
+ }
+ }
- break
+ // For 32-bit logical instruction with constant,
+ // rewrite the high 32-bit to be a repetition of
+ // the low 32-bit, so that the BITCON test can be
+ // shared for both 32-bit and 64-bit. 32-bit ops
+ // will zero the high 32-bit of the destination
+ // register anyway.
+ switch p.As {
+ case AANDW, AORRW, AEORW, AANDSW:
+ if p.From.Type == obj.TYPE_CONST {
+ v := p.From.Offset & 0xffffffff
+ p.From.Offset = v | v<<32
+ }
}
if ctxt.Flag_dynlink {