Skip to content

[M68k] add 32 bit branch instrs and relaxations #117371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2024

Conversation

knickish
Copy link
Contributor

@knickish knickish commented Nov 22, 2024

The Bcc and BRA 32-bit variants were all either not present or not used, and the BSR32 instruction was incorrectly being used on < M68020 cpu types. This PR adds missing 32 bit branch instructions (with the AtLeastM68020 predicate) and updates M68kAsmBackend to allow relaxation to these instructions when an M68020 or greater is targeted

@knickish knickish changed the title [M68k] add 32 bit branch instrs and allow x20 and later CPUs to relax… [M68k] add 32 bit branch instrs and relaxations Nov 22, 2024
Copy link

github-actions bot commented Nov 22, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@knickish knickish force-pushed the m68k_32_bit_branches branch 3 times, most recently from fa024dc to 9400bff Compare November 30, 2024 20:33
@knickish knickish marked this pull request as ready for review November 30, 2024 20:33
@llvmbot llvmbot added mc Machine (object) code backend:m68k labels Nov 30, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2024

@llvm/pr-subscribers-backend-m68k

Author: None (knickish)

Changes

The Bcc and BRA 32-bit variants were all either not present or not used, and the BSR32 instruction was incorrectly being used on < M68020 cpu types. This PR adds missing 32 bit branch instructions (with the AtLeastM68020 predicate) and updates M68kAsmBackend to allow relaxation to these instructions when an M68020 or greater is targeted


Full diff: https://github.com/llvm/llvm-project/pull/117371.diff

6 Files Affected:

  • (modified) llvm/lib/Target/M68k/M68kInstrControl.td (+13)
  • (modified) llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp (+71-10)
  • (modified) llvm/test/MC/M68k/Control/bsr.s (-11)
  • (added) llvm/test/MC/M68k/Control/bsr32.s (+35)
  • (added) llvm/test/MC/M68k/Relaxations/branch32.s (+63)
  • (modified) llvm/test/MC/M68k/Relocations/text-plt.s (+2-2)
diff --git a/llvm/lib/Target/M68k/M68kInstrControl.td b/llvm/lib/Target/M68k/M68kInstrControl.td
index 6e116d7cfe4019..4e94b2ed3a0645 100644
--- a/llvm/lib/Target/M68k/M68kInstrControl.td
+++ b/llvm/lib/Target/M68k/M68kInstrControl.td
@@ -179,6 +179,8 @@ class MxBcc<string cc, Operand TARGET, dag disp_8, dag disp_16_32>
         (descend 0b0110, !cast<MxEncCondOp>("MxCC"#cc).Value, disp_8),
         disp_16_32
       );
+
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
@@ -190,6 +192,10 @@ foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
   def B#cc#"16"
     : MxBcc<cc, MxBrTarget16, (descend 0b0000, 0b0000),
             (operand "$dst", 16, (encoder "encodePCRelImm<16>"))>;
+
+  def B#cc#"32"
+    : MxBcc<cc, MxBrTarget32, (descend 0b1111, 0b1111),
+            (operand "$dst", 32, (encoder "encodePCRelImm<32>"))>;
 }
 
 foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
@@ -215,6 +221,8 @@ class MxBra<Operand TARGET, dag disp_8, dag disp_16_32>
       (descend 0b0110, 0b0000, disp_8),
       disp_16_32
     );
+  
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 def BRA8  : MxBra<MxBrTarget8,
@@ -223,6 +231,10 @@ def BRA8  : MxBra<MxBrTarget8,
 def BRA16 : MxBra<MxBrTarget16, (descend 0b0000, 0b0000),
                   (operand "$dst", 16, (encoder "encodePCRelImm<16>"))>;
 
+def BRA32 : MxBra<MxBrTarget32, (descend 0b1111, 0b1111),
+                  (operand "$dst", 32, (encoder "encodePCRelImm<32>"),
+                                       (decoder "DecodeImm32"))>;
+
 def : Pat<(br bb:$target), (BRA8 MxBrTarget8:$target)>;
 
 /// -------------------------------------------------
@@ -242,6 +254,7 @@ class MxBsr<Operand TARGET, MxType TYPE, dag disp_8, dag disp_16_32>
                 (descend 0b0110, 0b0001, disp_8),
                  disp_16_32
               );
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 def BSR8 : MxBsr<MxBrTarget8, MxType8,
diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
index 2c52fe07bb1119..298ec1cfc7c539 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
@@ -30,18 +30,26 @@
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
+#define DEBUG_TYPE "M68k-asm-backend"
+
 namespace {
 
 class M68kAsmBackend : public MCAsmBackend {
+  bool Allows32BitBranch;
 
 public:
-  M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {}
+  M68kAsmBackend(const Target &T, const MCSubtargetInfo &STI)
+      : MCAsmBackend(llvm::endianness::big),
+        Allows32BitBranch(llvm::StringSwitch<bool>(STI.getCPU())
+                              .CasesLower("m68020", "m68030", "m68040", true)
+                              .Default(false)) {}
 
   unsigned getNumFixupKinds() const override { return 0; }
 
@@ -51,14 +59,26 @@ class M68kAsmBackend : public MCAsmBackend {
                   const MCSubtargetInfo *STI) const override {
     unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
 
-    assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
+    if (Fixup.getOffset() + Size > Data.size()) {
+      LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
+      LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
+      LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
+      assert(Fixup.getOffset() + Size <= Data.size() &&
+             "Invalid fixup offset!");
+    }
 
     // Check that uppper bits are either all zeros or all ones.
     // Specifically ignore overflow/underflow as long as the leakage is
     // limited to the lower bits. This is to remain compatible with
     // other assemblers.
-    assert(isIntN(Size * 8 + 1, Value) &&
-           "Value does not fit in the Fixup field");
+    if (!isIntN(Size * 8 + 1, Value)) {
+      LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
+      LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
+      LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
+      LLVM_DEBUG(dbgs() << "Value: " << Value << '\n');
+      assert(isIntN(Size * 8 + 1, Value) &&
+             "Value does not fit in the Fixup field");
+    }
 
     // Write in Big Endian
     for (unsigned i = 0; i != Size; ++i)
@@ -99,6 +119,8 @@ static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
   switch (Op) {
   default:
     return Op;
+
+  // 8 -> 16
   case M68k::BRA8:
     return M68k::BRA16;
   case M68k::Bcc8:
@@ -129,6 +151,38 @@ static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
     return M68k::Ble16;
   case M68k::Bvs8:
     return M68k::Bvs16;
+
+  // 16 -> 32
+  case M68k::BRA16:
+    return M68k::BRA32;
+  case M68k::Bcc16:
+    return M68k::Bcc32;
+  case M68k::Bls16:
+    return M68k::Bls32;
+  case M68k::Blt16:
+    return M68k::Blt32;
+  case M68k::Beq16:
+    return M68k::Beq32;
+  case M68k::Bmi16:
+    return M68k::Bmi32;
+  case M68k::Bne16:
+    return M68k::Bne32;
+  case M68k::Bge16:
+    return M68k::Bge32;
+  case M68k::Bcs16:
+    return M68k::Bcs32;
+  case M68k::Bpl16:
+    return M68k::Bpl32;
+  case M68k::Bgt16:
+    return M68k::Bgt32;
+  case M68k::Bhi16:
+    return M68k::Bhi32;
+  case M68k::Bvc16:
+    return M68k::Bvc32;
+  case M68k::Ble16:
+    return M68k::Ble32;
+  case M68k::Bvs16:
+    return M68k::Bvs32;
   }
 }
 
@@ -167,8 +221,7 @@ bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
 
 bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
                                           uint64_t Value) const {
-  // TODO Newer CPU can use 32 bit offsets, so check for this when ready
-  if (!isInt<16>(Value)) {
+  if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value))) {
     llvm_unreachable("Cannot relax the instruction, value does not fit");
   }
   // Relax if the value is too big for a (signed) i8. This means that byte-wide
@@ -178,7 +231,15 @@ bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
   // A branch to the immediately following instruction automatically
   // uses the 16-bit displacement format because the 8-bit
   // displacement field contains $00 (zero offset).
-  return Value == 0 || !isInt<8>(Value);
+  unsigned int KindLog2Size = getFixupKindLog2Size(Fixup.getKind());
+  bool FixupFieldTooSmall = false;
+  if (!isInt<8>(Value) && KindLog2Size == 0) {
+    FixupFieldTooSmall |= true;
+  } else if (!isInt<16>(Value) && KindLog2Size <= 1) {
+    FixupFieldTooSmall |= true;
+  }
+
+  return Value == 0 || FixupFieldTooSmall;
 }
 
 // NOTE Can tblgen help at all here to verify there aren't other instructions
@@ -218,8 +279,8 @@ namespace {
 class M68kELFAsmBackend : public M68kAsmBackend {
 public:
   uint8_t OSABI;
-  M68kELFAsmBackend(const Target &T, uint8_t OSABI)
-      : M68kAsmBackend(T), OSABI(OSABI) {}
+  M68kELFAsmBackend(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI)
+      : M68kAsmBackend(T, STI), OSABI(OSABI) {}
 
   std::unique_ptr<MCObjectTargetWriter>
   createObjectTargetWriter() const override {
@@ -235,5 +296,5 @@ MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
                                          const MCTargetOptions &Options) {
   const Triple &TheTriple = STI.getTargetTriple();
   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
-  return new M68kELFAsmBackend(T, OSABI);
+  return new M68kELFAsmBackend(T, STI, OSABI);
 }
diff --git a/llvm/test/MC/M68k/Control/bsr.s b/llvm/test/MC/M68k/Control/bsr.s
index a70c7fb9a96edf..6b7a7d5c6ecd94 100644
--- a/llvm/test/MC/M68k/Control/bsr.s
+++ b/llvm/test/MC/M68k/Control/bsr.s
@@ -8,10 +8,6 @@
 	; CHECK-SAME: encoding: [0x61,0x00,A,A]
         ; CHECK:      fixup A - offset: 2, value: .LBB0_2, kind: FK_PCRel_2
 	bsr.w	.LBB0_2
-  ; CHECK:     bsr.l   .LBB0_3
-  ; CHECK-SAME: encoding: [0x61,0xff,A,A,A,A] 
-        ; CHECK:      fixup A - offset: 2, value: .LBB0_3, kind: FK_PCRel_4
-  bsr.l .LBB0_3  
 .LBB0_1:
 	; CHECK:      add.l  #0, %d0
 	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x00]
@@ -26,10 +22,3 @@
 	; CHECK:      rts
 	; CHECK-SAME: encoding: [0x4e,0x75]
 	rts
-.LBB0_3:
-	; CHECK:      add.l  #1, %d0
-	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
-	add.l	#1, %d0
-	; CHECK:      rts
-	; CHECK-SAME: encoding: [0x4e,0x75]
-	rts
diff --git a/llvm/test/MC/M68k/Control/bsr32.s b/llvm/test/MC/M68k/Control/bsr32.s
new file mode 100644
index 00000000000000..58ed4a29a35318
--- /dev/null
+++ b/llvm/test/MC/M68k/Control/bsr32.s
@@ -0,0 +1,35 @@
+; RUN: llvm-mc -triple=m68k --mcpu=M68020 -show-encoding %s | FileCheck %s
+
+	; CHECK:      bsr.b   .LBB0_1
+	; CHECK-SAME: encoding: [0x61,A]
+        ; CHECK:      fixup A - offset: 1, value: .LBB0_1-1, kind: FK_PCRel_1
+	bsr.b .LBB0_1
+	; CHECK:      bsr.w   .LBB0_2
+	; CHECK-SAME: encoding: [0x61,0x00,A,A]
+        ; CHECK:      fixup A - offset: 2, value: .LBB0_2, kind: FK_PCRel_2
+	bsr.w	.LBB0_2
+  ; CHECK:     bsr.l   .LBB0_3
+  ; CHECK-SAME: encoding: [0x61,0xff,A,A,A,A] 
+        ; CHECK:      fixup A - offset: 2, value: .LBB0_3, kind: FK_PCRel_4
+  bsr.l .LBB0_3  
+.LBB0_1:
+	; CHECK:      add.l  #0, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x00]
+	add.l	#0, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
+.LBB0_2:
+	; CHECK:      add.l  #1, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
+	add.l	#1, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
+.LBB0_3:
+	; CHECK:      add.l  #1, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
+	add.l	#1, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
diff --git a/llvm/test/MC/M68k/Relaxations/branch32.s b/llvm/test/MC/M68k/Relaxations/branch32.s
new file mode 100644
index 00000000000000..d8bb3d40e639e8
--- /dev/null
+++ b/llvm/test/MC/M68k/Relaxations/branch32.s
@@ -0,0 +1,63 @@
+; RUN: llvm-mc -triple=m68k --mcpu=M68020 -motorola-integers -filetype=obj < %s \
+; RUN:     | llvm-objdump -d - | FileCheck %s
+
+; CHECK-LABEL: <TIGHT>:
+TIGHT:
+	; CHECK: bra  $78
+	bra	.LBB0_2
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+.LBB0_2:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <RELAXED>:
+RELAXED:
+	; CHECK: bra  $84
+	bra	.LBB1_2
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+.LBB1_2:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <RELAXED_32>:
+RELAXED_32:
+	; CHECK: bra  $ff
+	; CHECK-NEXT: 00 02
+	; CHECK-NEXT: 00 00
+	bra	.LBB3_1
+	.space 0x20000  ; Greater than u16::MAX.
+.LBB2_1:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <ZERO>:
+ZERO:
+	; CHECK: bra  $2
+	bra	.LBB3_1
+.LBB3_1:
+	add.l	#0, %d0
+	rts
+
diff --git a/llvm/test/MC/M68k/Relocations/text-plt.s b/llvm/test/MC/M68k/Relocations/text-plt.s
index 9513519c33c670..7de04b8b2182a5 100644
--- a/llvm/test/MC/M68k/Relocations/text-plt.s
+++ b/llvm/test/MC/M68k/Relocations/text-plt.s
@@ -1,6 +1,6 @@
-; RUN: llvm-mc -triple m68k -filetype=obj %s -o - \
+; RUN: llvm-mc -triple m68k --mcpu=M68020 -filetype=obj %s -o - \
 ; RUN:   | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
-; RUN: llvm-mc -triple m68k -show-encoding %s -o - \
+; RUN: llvm-mc -triple m68k --mcpu=M68020 -show-encoding %s -o - \
 ; RUN:   | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
 
 ; RELOC: R_68K_PLT16 target 0x0

@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2024

@llvm/pr-subscribers-mc

Author: None (knickish)

Changes

The Bcc and BRA 32-bit variants were all either not present or not used, and the BSR32 instruction was incorrectly being used on < M68020 cpu types. This PR adds missing 32 bit branch instructions (with the AtLeastM68020 predicate) and updates M68kAsmBackend to allow relaxation to these instructions when an M68020 or greater is targeted


Full diff: https://github.com/llvm/llvm-project/pull/117371.diff

6 Files Affected:

  • (modified) llvm/lib/Target/M68k/M68kInstrControl.td (+13)
  • (modified) llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp (+71-10)
  • (modified) llvm/test/MC/M68k/Control/bsr.s (-11)
  • (added) llvm/test/MC/M68k/Control/bsr32.s (+35)
  • (added) llvm/test/MC/M68k/Relaxations/branch32.s (+63)
  • (modified) llvm/test/MC/M68k/Relocations/text-plt.s (+2-2)
diff --git a/llvm/lib/Target/M68k/M68kInstrControl.td b/llvm/lib/Target/M68k/M68kInstrControl.td
index 6e116d7cfe4019..4e94b2ed3a0645 100644
--- a/llvm/lib/Target/M68k/M68kInstrControl.td
+++ b/llvm/lib/Target/M68k/M68kInstrControl.td
@@ -179,6 +179,8 @@ class MxBcc<string cc, Operand TARGET, dag disp_8, dag disp_16_32>
         (descend 0b0110, !cast<MxEncCondOp>("MxCC"#cc).Value, disp_8),
         disp_16_32
       );
+
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
@@ -190,6 +192,10 @@ foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
   def B#cc#"16"
     : MxBcc<cc, MxBrTarget16, (descend 0b0000, 0b0000),
             (operand "$dst", 16, (encoder "encodePCRelImm<16>"))>;
+
+  def B#cc#"32"
+    : MxBcc<cc, MxBrTarget32, (descend 0b1111, 0b1111),
+            (operand "$dst", 32, (encoder "encodePCRelImm<32>"))>;
 }
 
 foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge",
@@ -215,6 +221,8 @@ class MxBra<Operand TARGET, dag disp_8, dag disp_16_32>
       (descend 0b0110, 0b0000, disp_8),
       disp_16_32
     );
+  
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 def BRA8  : MxBra<MxBrTarget8,
@@ -223,6 +231,10 @@ def BRA8  : MxBra<MxBrTarget8,
 def BRA16 : MxBra<MxBrTarget16, (descend 0b0000, 0b0000),
                   (operand "$dst", 16, (encoder "encodePCRelImm<16>"))>;
 
+def BRA32 : MxBra<MxBrTarget32, (descend 0b1111, 0b1111),
+                  (operand "$dst", 32, (encoder "encodePCRelImm<32>"),
+                                       (decoder "DecodeImm32"))>;
+
 def : Pat<(br bb:$target), (BRA8 MxBrTarget8:$target)>;
 
 /// -------------------------------------------------
@@ -242,6 +254,7 @@ class MxBsr<Operand TARGET, MxType TYPE, dag disp_8, dag disp_16_32>
                 (descend 0b0110, 0b0001, disp_8),
                  disp_16_32
               );
+  let Predicates = !if(!eq(TARGET, MxBrTarget32), [AtLeastM68020], []);
 }
 
 def BSR8 : MxBsr<MxBrTarget8, MxType8,
diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
index 2c52fe07bb1119..298ec1cfc7c539 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
@@ -30,18 +30,26 @@
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
+#define DEBUG_TYPE "M68k-asm-backend"
+
 namespace {
 
 class M68kAsmBackend : public MCAsmBackend {
+  bool Allows32BitBranch;
 
 public:
-  M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {}
+  M68kAsmBackend(const Target &T, const MCSubtargetInfo &STI)
+      : MCAsmBackend(llvm::endianness::big),
+        Allows32BitBranch(llvm::StringSwitch<bool>(STI.getCPU())
+                              .CasesLower("m68020", "m68030", "m68040", true)
+                              .Default(false)) {}
 
   unsigned getNumFixupKinds() const override { return 0; }
 
@@ -51,14 +59,26 @@ class M68kAsmBackend : public MCAsmBackend {
                   const MCSubtargetInfo *STI) const override {
     unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
 
-    assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
+    if (Fixup.getOffset() + Size > Data.size()) {
+      LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
+      LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
+      LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
+      assert(Fixup.getOffset() + Size <= Data.size() &&
+             "Invalid fixup offset!");
+    }
 
     // Check that uppper bits are either all zeros or all ones.
     // Specifically ignore overflow/underflow as long as the leakage is
     // limited to the lower bits. This is to remain compatible with
     // other assemblers.
-    assert(isIntN(Size * 8 + 1, Value) &&
-           "Value does not fit in the Fixup field");
+    if (!isIntN(Size * 8 + 1, Value)) {
+      LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
+      LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
+      LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
+      LLVM_DEBUG(dbgs() << "Value: " << Value << '\n');
+      assert(isIntN(Size * 8 + 1, Value) &&
+             "Value does not fit in the Fixup field");
+    }
 
     // Write in Big Endian
     for (unsigned i = 0; i != Size; ++i)
@@ -99,6 +119,8 @@ static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
   switch (Op) {
   default:
     return Op;
+
+  // 8 -> 16
   case M68k::BRA8:
     return M68k::BRA16;
   case M68k::Bcc8:
@@ -129,6 +151,38 @@ static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
     return M68k::Ble16;
   case M68k::Bvs8:
     return M68k::Bvs16;
+
+  // 16 -> 32
+  case M68k::BRA16:
+    return M68k::BRA32;
+  case M68k::Bcc16:
+    return M68k::Bcc32;
+  case M68k::Bls16:
+    return M68k::Bls32;
+  case M68k::Blt16:
+    return M68k::Blt32;
+  case M68k::Beq16:
+    return M68k::Beq32;
+  case M68k::Bmi16:
+    return M68k::Bmi32;
+  case M68k::Bne16:
+    return M68k::Bne32;
+  case M68k::Bge16:
+    return M68k::Bge32;
+  case M68k::Bcs16:
+    return M68k::Bcs32;
+  case M68k::Bpl16:
+    return M68k::Bpl32;
+  case M68k::Bgt16:
+    return M68k::Bgt32;
+  case M68k::Bhi16:
+    return M68k::Bhi32;
+  case M68k::Bvc16:
+    return M68k::Bvc32;
+  case M68k::Ble16:
+    return M68k::Ble32;
+  case M68k::Bvs16:
+    return M68k::Bvs32;
   }
 }
 
@@ -167,8 +221,7 @@ bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
 
 bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
                                           uint64_t Value) const {
-  // TODO Newer CPU can use 32 bit offsets, so check for this when ready
-  if (!isInt<16>(Value)) {
+  if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value))) {
     llvm_unreachable("Cannot relax the instruction, value does not fit");
   }
   // Relax if the value is too big for a (signed) i8. This means that byte-wide
@@ -178,7 +231,15 @@ bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
   // A branch to the immediately following instruction automatically
   // uses the 16-bit displacement format because the 8-bit
   // displacement field contains $00 (zero offset).
-  return Value == 0 || !isInt<8>(Value);
+  unsigned int KindLog2Size = getFixupKindLog2Size(Fixup.getKind());
+  bool FixupFieldTooSmall = false;
+  if (!isInt<8>(Value) && KindLog2Size == 0) {
+    FixupFieldTooSmall |= true;
+  } else if (!isInt<16>(Value) && KindLog2Size <= 1) {
+    FixupFieldTooSmall |= true;
+  }
+
+  return Value == 0 || FixupFieldTooSmall;
 }
 
 // NOTE Can tblgen help at all here to verify there aren't other instructions
@@ -218,8 +279,8 @@ namespace {
 class M68kELFAsmBackend : public M68kAsmBackend {
 public:
   uint8_t OSABI;
-  M68kELFAsmBackend(const Target &T, uint8_t OSABI)
-      : M68kAsmBackend(T), OSABI(OSABI) {}
+  M68kELFAsmBackend(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI)
+      : M68kAsmBackend(T, STI), OSABI(OSABI) {}
 
   std::unique_ptr<MCObjectTargetWriter>
   createObjectTargetWriter() const override {
@@ -235,5 +296,5 @@ MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
                                          const MCTargetOptions &Options) {
   const Triple &TheTriple = STI.getTargetTriple();
   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
-  return new M68kELFAsmBackend(T, OSABI);
+  return new M68kELFAsmBackend(T, STI, OSABI);
 }
diff --git a/llvm/test/MC/M68k/Control/bsr.s b/llvm/test/MC/M68k/Control/bsr.s
index a70c7fb9a96edf..6b7a7d5c6ecd94 100644
--- a/llvm/test/MC/M68k/Control/bsr.s
+++ b/llvm/test/MC/M68k/Control/bsr.s
@@ -8,10 +8,6 @@
 	; CHECK-SAME: encoding: [0x61,0x00,A,A]
         ; CHECK:      fixup A - offset: 2, value: .LBB0_2, kind: FK_PCRel_2
 	bsr.w	.LBB0_2
-  ; CHECK:     bsr.l   .LBB0_3
-  ; CHECK-SAME: encoding: [0x61,0xff,A,A,A,A] 
-        ; CHECK:      fixup A - offset: 2, value: .LBB0_3, kind: FK_PCRel_4
-  bsr.l .LBB0_3  
 .LBB0_1:
 	; CHECK:      add.l  #0, %d0
 	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x00]
@@ -26,10 +22,3 @@
 	; CHECK:      rts
 	; CHECK-SAME: encoding: [0x4e,0x75]
 	rts
-.LBB0_3:
-	; CHECK:      add.l  #1, %d0
-	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
-	add.l	#1, %d0
-	; CHECK:      rts
-	; CHECK-SAME: encoding: [0x4e,0x75]
-	rts
diff --git a/llvm/test/MC/M68k/Control/bsr32.s b/llvm/test/MC/M68k/Control/bsr32.s
new file mode 100644
index 00000000000000..58ed4a29a35318
--- /dev/null
+++ b/llvm/test/MC/M68k/Control/bsr32.s
@@ -0,0 +1,35 @@
+; RUN: llvm-mc -triple=m68k --mcpu=M68020 -show-encoding %s | FileCheck %s
+
+	; CHECK:      bsr.b   .LBB0_1
+	; CHECK-SAME: encoding: [0x61,A]
+        ; CHECK:      fixup A - offset: 1, value: .LBB0_1-1, kind: FK_PCRel_1
+	bsr.b .LBB0_1
+	; CHECK:      bsr.w   .LBB0_2
+	; CHECK-SAME: encoding: [0x61,0x00,A,A]
+        ; CHECK:      fixup A - offset: 2, value: .LBB0_2, kind: FK_PCRel_2
+	bsr.w	.LBB0_2
+  ; CHECK:     bsr.l   .LBB0_3
+  ; CHECK-SAME: encoding: [0x61,0xff,A,A,A,A] 
+        ; CHECK:      fixup A - offset: 2, value: .LBB0_3, kind: FK_PCRel_4
+  bsr.l .LBB0_3  
+.LBB0_1:
+	; CHECK:      add.l  #0, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x00]
+	add.l	#0, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
+.LBB0_2:
+	; CHECK:      add.l  #1, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
+	add.l	#1, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
+.LBB0_3:
+	; CHECK:      add.l  #1, %d0
+	; CHECK-SAME: encoding: [0xd0,0xbc,0x00,0x00,0x00,0x01]
+	add.l	#1, %d0
+	; CHECK:      rts
+	; CHECK-SAME: encoding: [0x4e,0x75]
+	rts
diff --git a/llvm/test/MC/M68k/Relaxations/branch32.s b/llvm/test/MC/M68k/Relaxations/branch32.s
new file mode 100644
index 00000000000000..d8bb3d40e639e8
--- /dev/null
+++ b/llvm/test/MC/M68k/Relaxations/branch32.s
@@ -0,0 +1,63 @@
+; RUN: llvm-mc -triple=m68k --mcpu=M68020 -motorola-integers -filetype=obj < %s \
+; RUN:     | llvm-objdump -d - | FileCheck %s
+
+; CHECK-LABEL: <TIGHT>:
+TIGHT:
+	; CHECK: bra  $78
+	bra	.LBB0_2
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+.LBB0_2:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <RELAXED>:
+RELAXED:
+	; CHECK: bra  $84
+	bra	.LBB1_2
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+	move.l	$0, $0
+.LBB1_2:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <RELAXED_32>:
+RELAXED_32:
+	; CHECK: bra  $ff
+	; CHECK-NEXT: 00 02
+	; CHECK-NEXT: 00 00
+	bra	.LBB3_1
+	.space 0x20000  ; Greater than u16::MAX.
+.LBB2_1:
+	add.l	#0, %d0
+	rts
+
+; CHECK-LABEL: <ZERO>:
+ZERO:
+	; CHECK: bra  $2
+	bra	.LBB3_1
+.LBB3_1:
+	add.l	#0, %d0
+	rts
+
diff --git a/llvm/test/MC/M68k/Relocations/text-plt.s b/llvm/test/MC/M68k/Relocations/text-plt.s
index 9513519c33c670..7de04b8b2182a5 100644
--- a/llvm/test/MC/M68k/Relocations/text-plt.s
+++ b/llvm/test/MC/M68k/Relocations/text-plt.s
@@ -1,6 +1,6 @@
-; RUN: llvm-mc -triple m68k -filetype=obj %s -o - \
+; RUN: llvm-mc -triple m68k --mcpu=M68020 -filetype=obj %s -o - \
 ; RUN:   | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
-; RUN: llvm-mc -triple m68k -show-encoding %s -o - \
+; RUN: llvm-mc -triple m68k --mcpu=M68020 -show-encoding %s -o - \
 ; RUN:   | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
 
 ; RELOC: R_68K_PLT16 target 0x0

@knickish knickish force-pushed the m68k_32_bit_branches branch 2 times, most recently from 5b91167 to ea5fef9 Compare December 2, 2024 18:51
@knickish
Copy link
Contributor Author

knickish commented Dec 2, 2024

Copied most of the relocation tests to run them with --position-independent, and added some encoding tests. Also included some small tweaks to behavior that I found necessary during manual testing using the rust core library with -fno-function-sections related to branch relaxation/fixups, and explicit casts for unsigned -> signed conversions. The original tests still pass, so no changes to existing functionality.

The encoding tests themselves aren't that helpful as the assembly is emitted before fixup relaxation happens for the branches. Might be good to change the branch instructions to pattern match based on size at some point instead of always matching the 8bit version and relaxing

@dianqk dianqk requested a review from mshockwave December 3, 2024 06:00
@knickish
Copy link
Contributor Author

knickish commented Dec 9, 2024

Ping

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM w/ minor comments
thanks

uint64_t UnsignedValue) const {
int64_t Value = static_cast<int64_t>(UnsignedValue);

if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I know the curly braces were already here, but could you drop them? (single statement shouldn't have curly braces)

// that byte-wide instructions have to matched by default
unsigned KindLog2Size = getFixupKindLog2Size(Fixup.getKind());
bool FixupFieldTooSmall = false;
if (!isInt<8>(Value) && KindLog2Size == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single statement should not have curly braces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed braces from both

@knickish knickish force-pushed the m68k_32_bit_branches branch from ea5fef9 to b125c0f Compare December 11, 2024 18:28
@mshockwave
Copy link
Member

Please don't force push unless necessary, append new commits instead (all commits will be squashed into one upon merging)

@mshockwave mshockwave merged commit 44c05a6 into llvm:main Dec 12, 2024
8 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 12, 2024

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/3331

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'LLVM :: MC/Disassembler/M68k/control.txt' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/llvm-mc -disassemble -triple m68k /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt | /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/FileCheck /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
+ /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/llvm-mc -disassemble -triple m68k /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
+ /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/FileCheck /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:23:11: warning: invalid instruction encoding
0x61 0xff 0x00 0x0f 0x00 0x01
          ^
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:23:21: warning: invalid instruction encoding
0x61 0xff 0x00 0x0f 0x00 0x01
                    ^
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:22:10: error: CHECK: expected string not found in input
# CHECK: bsr.l $f0001
         ^
<stdin>:9:12: note: scanning from here
 bsr.w $f01
           ^
<stdin>:10:2: note: possible intended match here
 bsr.b $ff
 ^

Input file: <stdin>
Check file: /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1:  .text 
            2:  bra $0 
            3:  jsr $0 
            4:  rts 
            5:  seq %d0 
            6:  sgt %d0 
            7:  nop 
            8:  bsr.b $1 
            9:  bsr.w $f01 
check:22'0                X error: no match found
           10:  bsr.b $ff 
check:22'0     ~~~~~~~~~~~
check:22'1      ?          possible intended match
>>>>>>

--

********************


@knickish
Copy link
Contributor Author

I guess llvm-lit doesn't run that test by default. The actual result looks fine, will make a follow-up pr to adjust the test

@knickish
Copy link
Contributor Author

Please don't force push unless necessary, append new commits instead (all commits will be squashed into one upon merging)

Understood, didn't realize they get squashed

@glaubitz
Copy link
Contributor

@knickish Your change has made the buildbot unhappy, unfortunately: https://lab.llvm.org/buildbot/#/builders/27/builds/3331

Can you have a look?

@glaubitz
Copy link
Contributor

Here is the error message from the testsuite:

******************** TEST 'LLVM :: MC/Disassembler/M68k/control.txt' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/llvm-mc -disassemble -triple m68k /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt | /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/FileCheck /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
+ /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/llvm-mc -disassemble -triple m68k /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
+ /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/bin/FileCheck /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:23:11: warning: invalid instruction encoding
0x61 0xff 0x00 0x0f 0x00 0x01
          ^
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:23:21: warning: invalid instruction encoding
0x61 0xff 0x00 0x0f 0x00 0x01
                    ^
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt:22:10: error: CHECK: expected string not found in input
# CHECK: bsr.l $f0001
         ^
<stdin>:9:12: note: scanning from here
 bsr.w $f01
           ^
<stdin>:10:2: note: possible intended match here
 bsr.b $ff
 ^

Input file: <stdin>
Check file: /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/test/MC/Disassembler/M68k/control.txt

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1:  .text 
            2:  bra $0 
            3:  jsr $0 
            4:  rts 
            5:  seq %d0 
            6:  sgt %d0 
            7:  nop 
            8:  bsr.b $1 
            9:  bsr.w $f01 
check:22'0                X error: no match found
           10:  bsr.b $ff 
check:22'0     ~~~~~~~~~~~
check:22'1      ?          possible intended match
>>>>>>

--

********************

@knickish
Copy link
Contributor Author

I guess llvm-lit doesn't run that test by default. The actual result looks fine, will make a follow-up pr to adjust the test

@glaubitz I can fix it in a few hours, does it need to be reverted before then?

@glaubitz
Copy link
Contributor

I guess llvm-lit doesn't run that test by default. The actual result looks fine, will make a follow-up pr to adjust the test

@glaubitz I can fix it in a few hours, does it need to be reverted before then?

Nah, I think that should be fine. I assume you're currently getting error mails because of it.

@knickish
Copy link
Contributor Author

Have a PR up to fix this now. #119758

mshockwave pushed a commit that referenced this pull request Dec 12, 2024
…19758)

Fixes test failure reported in #117371. `BSR32` was previously
(incorrectly) allowed for CPUs <M68020, this test was missed while
updating the rest to fit the new model
qiaojbao pushed a commit to GPUOpen-Drivers/llvm-project that referenced this pull request Dec 23, 2024
Local branch amd-gfx 3a0701c Merged main:5e007afa9d4f into amd-gfx:4c17e1c71592
Remote branch main 44c05a6 [M68k] add 32 bit branch instrs and relaxations (llvm#117371)
uint64_t UnsignedValue) const {
int64_t Value = static_cast<int64_t>(UnsignedValue);

if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value)))
llvm_unreachable("Cannot relax the instruction, value does not fit");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should be a cleaner error than an unreachable? You can trip this easily by compiling 32-bit-okay code for a 16-bit-only device

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you prefer it to be an assert instead of llvm_unreachable, or something more detailed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:m68k mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants