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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions llvm/lib/Target/M68k/M68kInstrControl.td
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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,
Expand All @@ -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)>;

/// -------------------------------------------------
Expand All @@ -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,
Expand Down
102 changes: 85 additions & 17 deletions llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,28 @@
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCValue.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; }

Expand All @@ -51,18 +60,34 @@ 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, static_cast<int64_t>(Value)) || IsResolved)) {
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');
LLVM_DEBUG(dbgs() << "Target: ");
LLVM_DEBUG(Target.print(dbgs()));
LLVM_DEBUG(dbgs() << '\n');
assert(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) &&
"Value does not fit in the Fixup field");
}

// Write in Big Endian
for (unsigned i = 0; i != Size; ++i)
Data[Fixup.getOffset() + i] = uint8_t(Value >> ((Size - i - 1) * 8));
Data[Fixup.getOffset() + i] =
uint8_t(static_cast<int64_t>(Value) >> ((Size - i - 1) * 8));
}

bool mayNeedRelaxation(const MCInst &Inst,
Expand Down Expand Up @@ -99,6 +124,8 @@ static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
switch (Op) {
default:
return Op;

// 8 -> 16
case M68k::BRA8:
return M68k::BRA16;
case M68k::Bcc8:
Expand Down Expand Up @@ -129,6 +156,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;
}
}

Expand Down Expand Up @@ -166,26 +225,35 @@ 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)) {
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?

}
// Relax if the value is too big for a (signed) i8. This means that byte-wide
// instructions have to matched by default
//

// Relax if the value is too big for a (signed) i8
// (or signed i16 if 32 bit branches can be used). This means
// that byte-wide instructions have to matched by default
unsigned KindLog2Size = getFixupKindLog2Size(Fixup.getKind());
bool FixupFieldTooSmall = false;
if (!isInt<8>(Value) && KindLog2Size == 0)
FixupFieldTooSmall = true;
else if (!isInt<16>(Value) && KindLog2Size <= 1)
FixupFieldTooSmall = true;

// NOTE
// 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);
bool ZeroDisplacementNeedsFixup = Value == 0 && KindLog2Size == 0;

return ZeroDisplacementNeedsFixup || FixupFieldTooSmall;
}

// NOTE Can tblgen help at all here to verify there aren't other instructions
// we can relax?
void M68kAsmBackend::relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const {
// The only relaxations M68k does is from a 1byte pcrel to a 2byte PCRel.
unsigned RelaxedOp = getRelaxedOpcode(Inst);

if (RelaxedOp == Inst.getOpcode()) {
Expand Down Expand Up @@ -218,8 +286,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 {
Expand All @@ -235,5 +303,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);
}
11 changes: 0 additions & 11 deletions llvm/test/MC/M68k/Control/bsr.s
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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
35 changes: 35 additions & 0 deletions llvm/test/MC/M68k/Control/bsr32.s
Original file line number Diff line number Diff line change
@@ -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
38 changes: 38 additions & 0 deletions llvm/test/MC/M68k/Relaxations/PIC/branch.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
; RUN: llvm-mc -triple=m68k -motorola-integers -filetype=obj --position-independent < %s \
; RUN: | llvm-objdump -d - | FileCheck %s
; RUN: llvm-mc -triple m68k -show-encoding --position-independent %s -o - \
; RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s

; CHECK-LABEL: <TIGHT>:
TIGHT:
; CHECK: bra $7f
; INSTR: bra .LBB0_2 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB0_2-1, kind: FK_PCRel_1
bra .LBB0_2
.space 0x7F ; i8::MAX
.LBB0_2:
add.l #0, %d0
rts

; CHECK-LABEL: <RELAXED>:
RELAXED:
; CHECK: bra $82
; INSTR: bra .LBB1_2 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB1_2-1, kind: FK_PCRel_1
bra .LBB1_2
.space 0x80 ; Greater than i8::MAX
.LBB1_2:
add.l #0, %d0
rts

; CHECK-LABEL: <ZERO>:
ZERO:
; CHECK: bra $2
; INSTR: bra .LBB3_1 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB3_1-1, kind: FK_PCRel_1
bra .LBB3_1
.LBB3_1:
add.l #0, %d0
rts


53 changes: 53 additions & 0 deletions llvm/test/MC/M68k/Relaxations/PIC/branch32.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
; RUN: llvm-mc -triple=m68k --mcpu=M68020 -motorola-integers -filetype=obj --position-independent < %s \
; RUN: | llvm-objdump -d - | FileCheck %s
; RUN: llvm-mc -triple m68k --mcpu=M68020 -show-encoding --position-independent %s -o - \
; RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s

; Branch relocations are relaxed as part of object layout, so -show-encoding still
; shows them as 1-byte relocactions

; CHECK-LABEL: <TIGHT>:
TIGHT:
; CHECK: bra $7f
; INSTR: bra .LBB0_2 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB0_2-1, kind: FK_PCRel_1
bra .LBB0_2
.space 0x7F ; i8::MAX
.LBB0_2:
add.l #0, %d0
rts

; CHECK-LABEL: <RELAXED>:
RELAXED:
; CHECK: bra $82
; INSTR: bra .LBB1_2 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB1_2-1, kind: FK_PCRel_1
bra .LBB1_2
.space 0x80 ; Greater than i8::MAX
.LBB1_2:
add.l #0, %d0
rts

; CHECK-LABEL: <RELAXED_32>:
RELAXED_32:
; CHECK: bra $ff
; CHECK-NEXT: 00 00
; CHECK-NEXT: 80 04
; INSTR: bra .LBB2_1 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB2_1-1, kind: FK_PCRel_1
bra .LBB2_1
.space 0x8000 ; Greater than i16::MAX.
.LBB2_1:
add.l #0, %d0
rts

; CHECK-LABEL: <ZERO>:
ZERO:
; CHECK: bra $2
; INSTR: bra .LBB3_1 ; encoding: [0x60,A]
; FIXUP: fixup A - offset: 1, value: .LBB3_1-1, kind: FK_PCRel_1
bra .LBB3_1
.LBB3_1:
add.l #0, %d0
rts

Loading
Loading