[SPARC][MC] Fix encoding of backwards BPr branches

Make sure that the upper bits of the offset is placed in bits 20-21 of the
instruction word.

This fixes the encoding of backwards (negative offset) BPr branches.

(Previously, the upper two bits of the offset would overwrite parts of the rs1
field, causing it to branch on the wrong register, with the wrong offset)

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D144012
This commit is contained in:
Brad Smith
2023-04-26 18:53:52 -04:00
parent c30c291887
commit 92f1156efc
6 changed files with 75 additions and 48 deletions

View File

@@ -41,11 +41,14 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
case Sparc::fixup_sparc_br19:
return (Value >> 2) & 0x7ffff;
case Sparc::fixup_sparc_br16_2:
return (Value >> 2) & 0xc000;
case Sparc::fixup_sparc_br16_14:
return (Value >> 2) & 0x3fff;
case Sparc::fixup_sparc_br16: {
// A.3 Branch on Integer Register with Prediction (BPr)
// Inst{21-20} = d16hi;
// Inst{13-0} = d16lo;
unsigned d16hi = (Value >> 16) & 0x3;
unsigned d16lo = (Value >> 2) & 0x3fff;
return (d16hi << 20) | d16lo;
}
case Sparc::fixup_sparc_hix22:
return (~Value >> 10) & 0x3fffff;
@@ -164,8 +167,7 @@ namespace {
{ "fixup_sparc_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_2", 10, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_14", 18, 14, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_13", 19, 13, 0 },
{ "fixup_sparc_hi22", 10, 22, 0 },
{ "fixup_sparc_lo10", 22, 10, 0 },
@@ -211,8 +213,7 @@ namespace {
{ "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_2", 20, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_14", 0, 14, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16", 32, 0, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_13", 0, 13, 0 },
{ "fixup_sparc_hi22", 0, 22, 0 },
{ "fixup_sparc_lo10", 0, 10, 0 },
@@ -345,9 +346,16 @@ namespace {
if (Fixup.getKind() >= FirstLiteralRelocationKind)
return;
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
Value = adjustFixupValue(Fixup.getKind(), Value);
if (!Value) return; // Doesn't change encoding.
// Shift the value into position.
if (Endian == support::little)
Value <<= Info.TargetOffset;
else
Value <<= 32 - Info.TargetOffset - Info.TargetSize;
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
unsigned Offset = Fixup.getOffset();
// For each byte of the fragment that the fixup touches, mask in the bits

View File

@@ -62,6 +62,8 @@ unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx,
case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30;
case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22;
case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19;
case Sparc::fixup_sparc_br16:
return ELF::R_SPARC_WDISP16;
case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22;
case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10;
case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30;

View File

@@ -26,8 +26,7 @@ namespace llvm {
fixup_sparc_br19,
/// fixup_sparc_bpr - 16-bit fixup for bpr
fixup_sparc_br16_2,
fixup_sparc_br16_14,
fixup_sparc_br16,
/// fixup_sparc_13 - 13-bit fixup
fixup_sparc_13,

View File

@@ -235,10 +235,8 @@ getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Sparc::fixup_sparc_br16_2));
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Sparc::fixup_sparc_br16_14));
Fixups.push_back(
MCFixup::create(0, MO.getExpr(), (MCFixupKind)Sparc::fixup_sparc_br16));
return 0;
}

View File

@@ -0,0 +1,31 @@
! RUN: llvm-mc -arch=sparcv9 -filetype=obj %s | llvm-objdump -d - | FileCheck %s --check-prefix=BIN
!! SPARCv9/SPARC64 BPr branches have different offset encoding from the others,
!! make sure that our offset bits don't trample on other fields.
!! This is particularly important with backwards branches.
! BIN: 0: 02 c8 40 01 brz %g1, 1
! BIN: 4: 04 c8 40 01 brlez %g1, 1
! BIN: 8: 06 c8 40 01 brlz %g1, 1
! BIN: c: 0a c8 40 01 brnz %g1, 1
! BIN: 10: 0c c8 40 01 brgz %g1, 1
! BIN: 14: 0e c8 40 01 brgez %g1, 1
brz %g1, .+4
brlez %g1, .+4
brlz %g1, .+4
brnz %g1, .+4
brgz %g1, .+4
brgez %g1, .+4
! BIN: 18: 02 f8 7f ff brz %g1, 65535
! BIN: 1c: 04 f8 7f ff brlez %g1, 65535
! BIN: 20: 06 f8 7f ff brlz %g1, 65535
! BIN: 24: 0a f8 7f ff brnz %g1, 65535
! BIN: 28: 0c f8 7f ff brgz %g1, 65535
! BIN: 2c: 0e f8 7f ff brgez %g1, 65535
brz %g1, .-4
brlez %g1, .-4
brlz %g1, .-4
brnz %g1, .-4
brgz %g1, .-4
brgez %g1, .-4

View File

@@ -1150,24 +1150,18 @@
fbne,a,pn %fcc3, .BB0
! CHECK: brz %g1, .BB0 ! encoding: [0x02,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brlez %g1, .BB0 ! encoding: [0x04,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brlz %g1, .BB0 ! encoding: [0x06,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brnz %g1, .BB0 ! encoding: [0x0a,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brgz %g1, .BB0 ! encoding: [0x0c,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brgez %g1, .BB0 ! encoding: [0x0e,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz %g1, .BB0 ! encoding: [0x02'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
! CHECK: brlez %g1, .BB0 ! encoding: [0x04'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
! CHECK: brlz %g1, .BB0 ! encoding: [0x06'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
! CHECK: brnz %g1, .BB0 ! encoding: [0x0a'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
! CHECK: brgz %g1, .BB0 ! encoding: [0x0c'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
! CHECK: brgez %g1, .BB0 ! encoding: [0x0e'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz %g1, .BB0
brlez %g1, .BB0
@@ -1176,29 +1170,24 @@
brgz %g1, .BB0
brgez %g1, .BB0
! CHECK: brz %g1, .BB0 ! encoding: [0x02,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz %g1, .BB0 ! encoding: [0x02'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz,pt %g1, .BB0
! CHECK: brz,a %g1, .BB0 ! encoding: [0x22,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz,a %g1, .BB0 ! encoding: [0x22'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz,a %g1, .BB0
! CHECK: brz,a %g1, .BB0 ! encoding: [0x22,0b11AA1000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz,a %g1, .BB0 ! encoding: [0x22'A',0xc8'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz,a,pt %g1, .BB0
! CHECK: brz,pn %g1, .BB0 ! encoding: [0x02,0b11AA0000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz,pn %g1, .BB0 ! encoding: [0x02'A',0xc0'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz,pn %g1, .BB0
! CHECK: brz,a,pn %g1, .BB0 ! encoding: [0x22,0b11AA0000,0b01BBBBBB,B]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16_2
! CHECK-NEXT: ! fixup B - offset: 0, value: .BB0, kind: fixup_sparc_br16_14
! CHECK: brz,a,pn %g1, .BB0 ! encoding: [0x22'A',0xc0'A',0x40'A',A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br16
brz,a,pn %g1, .BB0
! CHECK: movrz %g1, %g2, %g3 ! encoding: [0x87,0x78,0x44,0x02]