cmd/internal/obj/arm64: fix BITCON constant printing error

For some 32-bit instructions whose first operand is a constant, we
copy the lower 32 bits of the constant into the upper 32 bits in progedit,
which leads to the wrong value being printed in -S output.

The purpose of this is that we don't need to distinguish between 32-bit
and 64-bit constants when checking C_BITCON, this CL puts the modified
value in a temporary variable, so that the constant operand of the
instruction will not be modified.

Fixes #53551

Change-Id: I40ee9223b4187bff1c0a1bab7eb508fcb30325f9
Reviewed-on: https://go-review.googlesource.com/c/go/+/414374
Run-TryBot: Eric Fang <eric.fang@arm.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
eric fang 2022-06-26 09:39:09 +00:00 committed by Keith Randall
parent a30f434667
commit 160414ca6a
2 changed files with 16 additions and 18 deletions

View file

@ -1557,6 +1557,10 @@ func sequenceOfOnes(x uint64) bool {
// N=0, S=11110x -- period=2
// R is the shift amount, low bits of S = n-1
func bitconEncode(x uint64, mode int) uint32 {
if mode == 32 {
x &= 0xffffffff
x = x<<32 | x
}
var period uint32
// determine the period and sign-extend a unit to 64 bits
switch {
@ -1825,17 +1829,24 @@ func rclass(r int16) int {
// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
func (c *ctxt7) con32class(a *obj.Addr) int {
v := uint32(a.Offset)
// For 32-bit 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.
vbitcon := uint64(v)<<32 | uint64(v)
if v == 0 {
return C_ZCON
}
if isaddcon(int64(v)) {
if v <= 0xFFF {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_ABCON0
}
return C_ADDCON0
}
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_ABCON
}
if movcon(int64(v)) >= 0 {
@ -1849,7 +1860,7 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t := movcon(int64(v))
if t >= 0 {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_MBCON
}
return C_MOVCON
@ -1857,13 +1868,13 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t = movcon(int64(^v))
if t >= 0 {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_MBCON
}
return C_MOVCON
}
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_BITCON
}

View file

@ -382,19 +382,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
}
// For 32-bit 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.
// For MOVW, the destination register can't be ZR,
// so don't bother rewriting it in this situation.
if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW && p.To.Reg != REGZERO) && p.From.Type == obj.TYPE_CONST {
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
if c.ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
}