[SPARC][MC] Fix encoding of backwards BPr branches
authorBrad Smith <brad@comstyle.com>
Wed, 26 Apr 2023 22:53:52 +0000 (18:53 -0400)
committerBrad Smith <brad@comstyle.com>
Wed, 26 Apr 2023 22:56:01 +0000 (18:56 -0400)
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

llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
llvm/test/MC/Sparc/sparc64-bpr-offset.s [new file with mode: 0644]
llvm/test/MC/Sparc/sparc64-ctrl-instructions.s

index aa89488..9900af9 100644 (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
index 9c50c41..c48beab 100644 (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;
index 701d851..3b91326 100644 (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,
index ee46000..e69319f 100644 (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;
 }
diff --git a/llvm/test/MC/Sparc/sparc64-bpr-offset.s b/llvm/test/MC/Sparc/sparc64-bpr-offset.s
new file mode 100644 (file)
index 0000000..6c853c3
--- /dev/null
@@ -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
index 737b953..a21b175 100644 (file)
         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
         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]