[llvm] 53a2bf8 - [M68k][VarLenCodeEmitter] Support reloc & pc-rel immediate values
Min-Yih Hsu via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 15 20:45:02 PST 2022
Author: Min-Yih Hsu
Date: 2022-02-15T20:41:33-08:00
New Revision: 53a2bf8ac7c2d631f5a32157df0b701843e12de6
URL: https://github.com/llvm/llvm-project/commit/53a2bf8ac7c2d631f5a32157df0b701843e12de6
DIFF: https://github.com/llvm/llvm-project/commit/53a2bf8ac7c2d631f5a32157df0b701843e12de6.diff
LOG: [M68k][VarLenCodeEmitter] Support reloc & pc-rel immediate values
Supporting relocatable and pc-relative immediate values for the new code
emitter.
Differential Revision: https://reviews.llvm.org/D119101
Added:
llvm/test/MC/M68k/pc-rel.s
Modified:
llvm/lib/Target/M68k/M68kInstrFormats.td
llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/M68k/M68kInstrFormats.td b/llvm/lib/Target/M68k/M68kInstrFormats.td
index b3c4fdfe2f530..0518faa77a283 100644
--- a/llvm/lib/Target/M68k/M68kInstrFormats.td
+++ b/llvm/lib/Target/M68k/M68kInstrFormats.td
@@ -243,7 +243,8 @@ def MxEncEAk : MxEncEA<MxBead3Bits<0b011>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
def MxEncEAi : MxEncEA<MxBead3Bits<0b100>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
class MxEncBriefExt<string reg_opnd, string disp_opnd,
- bit size_w_l = false, int scale = 1> {
+ bit size_w_l = false, int scale = 1,
+ string disp_encoder = ""> {
dag Value = (descend
// D/A + REGISTER
(operand "$"#reg_opnd, 4),
@@ -258,16 +259,22 @@ class MxEncBriefExt<string reg_opnd, string disp_opnd,
),
0b0,
// Displacement
- (operand "$"#disp_opnd, 8)
+ (operand "$"#disp_opnd, 8, (encoder disp_encoder))
);
}
+class MxEncAddrMode_r<string reg_opnd> : MxEncMemOp {
+ let EA = (descend /*MODE without the last bit*/0b00,
+ /*REGISTER with D/A bit*/(operand "$"#reg_opnd, 4));
+}
+
class MxEncAddrMode_k<string opnd_name> : MxEncMemOp {
let EA = (descend /*MODE*/0b111,
- /*REGISTER*/0b011);
+ /*REGISTER*/0b011);
let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
- /*W/L*/true>.Value;
+ /*W/L*/true, /*SCALE*/1,
+ "encodePCRelImm<8>">.Value;
}
class MxEncAddrMode_q<string opnd_name> : MxEncMemOp {
@@ -275,7 +282,8 @@ class MxEncAddrMode_q<string opnd_name> : MxEncMemOp {
/*REGISTER*/0b010);
// 16-bit Displacement
- let Supplement = (operand "$"#opnd_name, 16);
+ let Supplement = (operand "$"#opnd_name, 16,
+ (encoder "encodePCRelImm<16>"));
}
class MxEncAddrMode_p<string opnd_name> : MxEncMemOp {
@@ -283,7 +291,8 @@ class MxEncAddrMode_p<string opnd_name> : MxEncMemOp {
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
// 16-bit Displacement
- let Supplement = (operand "$"#opnd_name#".disp", 16);
+ let Supplement = (operand "$"#opnd_name#".disp", 16,
+ (encoder "encodeRelocImm<16>"));
}
class MxEncAddrMode_f<string opnd_name> : MxEncMemOp {
@@ -291,7 +300,8 @@ class MxEncAddrMode_f<string opnd_name> : MxEncMemOp {
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
- /*W/L*/true>.Value;
+ /*W/L*/true, /*SCALE*/1,
+ "encodeRelocImm<8>">.Value;
}
class MxEncAddrMode_j<string reg_opnd> : MxEncMemOp {
@@ -322,10 +332,9 @@ class MxEncAddrMode_abs<string opnd_name, bit size_w_l = false> : MxEncMemOp {
// Absolute address
let Supplement = !if(size_w_l,
// abs.L
- (ascend (slice "$"#opnd_name, 31, 16),
- (slice "$"#opnd_name, 15, 0)),
+ (operand "$"#opnd_name, 32, (encoder "encodeRelocImm<32>")),
// abs.W
- (operand "$"#opnd_name, 16)
+ (operand "$"#opnd_name, 16, (encoder "encodeRelocImm<16>"))
);
}
diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
index c90126e52db0d..64c3c3324f3a3 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
+#include <type_traits>
using namespace llvm;
@@ -48,6 +49,16 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ template <unsigned Size>
+ void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
+ APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ template <unsigned Size>
+ void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
+ APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
public:
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {}
@@ -83,6 +94,122 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
#include "M68kGenMCCodeEmitter.inc"
+// Select the proper unsigned integer type from a bit size.
+template <unsigned Size> struct select_uint_t {
+ using type = typename std::conditional<
+ Size == 8, uint8_t,
+ typename std::conditional<
+ Size == 16, uint16_t,
+ typename std::conditional<Size == 32, uint32_t,
+ uint64_t>::type>::type>::type;
+};
+
+// On a LE host:
+// MSB LSB MSB LSB
+// | 0x12 0x34 | 0xAB 0xCD | -> | 0xAB 0xCD | 0x12 0x34 |
+// (On a BE host nothing changes)
+template <typename value_t> static value_t swapWord(value_t Val) {
+ const unsigned NumWords = sizeof(Val) / 2;
+ if (NumWords <= 1)
+ return Val;
+ Val = support::endian::byte_swap(Val, support::big);
+ value_t NewVal = 0;
+ for (unsigned i = 0U; i != NumWords; ++i) {
+ uint16_t Part = (Val >> (i * 16)) & 0xFFFF;
+ Part = support::endian::byte_swap(Part, support::big);
+ NewVal |= (Part << (i * 16));
+ }
+ return NewVal;
+}
+
+// Figure out which byte we're at in big endian mode.
+template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
+ if (Size % 16) {
+ return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
+ } else {
+ assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
+ return BitPos / 8;
+ }
+}
+
+// We need special handlings for relocatable & pc-relative operands that are
+// larger than a word.
+// A M68k instruction is aligned by word (16 bits). That means, 32-bit
+// (& 64-bit) immediate values are separated into hi & lo words and placed
+// at lower & higher addresses, respectively. For immediate values that can
+// be easily expressed in TG, we explicitly rotate the word ordering like
+// this:
+// ```
+// (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
+// ```
+// For operands that call into encoder functions, we need to use the `swapWord`
+// function to assure the correct word ordering on LE host. Note that
+// M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
+// instruction but it assumes everything aligns on word boundaries. So things
+// will go wrong if we don't take care of the _word_ ordering here.
+template <unsigned Size>
+void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
+ unsigned InsertPos, APInt &Value,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ using value_t = typename select_uint_t<Size>::type;
+ const MCOperand &MCO = MI.getOperand(OpIdx);
+ if (MCO.isImm()) {
+ Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
+ } else if (MCO.isExpr()) {
+ const MCExpr *Expr = MCO.getExpr();
+
+ // Absolute address
+ int64_t Addr;
+ if (Expr->evaluateAsAbsolute(Addr)) {
+ Value |= swapWord<value_t>(static_cast<value_t>(Addr));
+ return;
+ }
+
+ // Relocatable address
+ unsigned InsertByte = getBytePosition<Size>(InsertPos);
+ Fixups.push_back(MCFixup::create(InsertByte, Expr,
+ getFixupForSize(Size, /*IsPCRel=*/false),
+ MI.getLoc()));
+ }
+}
+
+template <unsigned Size>
+void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
+ unsigned InsertPos, APInt &Value,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MCO = MI.getOperand(OpIdx);
+ if (MCO.isImm()) {
+ using value_t = typename select_uint_t<Size>::type;
+ Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
+ } else if (MCO.isExpr()) {
+ const MCExpr *Expr = MCO.getExpr();
+ unsigned InsertByte = getBytePosition<Size>(InsertPos);
+
+ // Special handlings for sizes smaller than a word.
+ if (Size < 16) {
+ int LabelOffset = 0;
+ if (InsertPos < 16)
+ // If the patch point is at the first word, PC is pointing at the
+ // next word.
+ LabelOffset = InsertByte - 2;
+ else if (InsertByte % 2)
+ // Otherwise the PC is pointing at the first byte of this word.
+ // So we need to consider the offset between PC and the fixup byte.
+ LabelOffset = 1;
+
+ if (LabelOffset)
+ Expr = MCBinaryExpr::createAdd(
+ Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
+ }
+
+ Fixups.push_back(MCFixup::create(InsertByte, Expr,
+ getFixupForSize(Size, /*IsPCRel=*/true),
+ MI.getLoc()));
+ }
+}
+
void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
@@ -98,6 +225,13 @@ void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
} else if (Op.isImm()) {
// Immediate
Value |= static_cast<uint64_t>(Op.getImm());
+ } else if (Op.isExpr()) {
+ // Absolute address
+ int64_t Addr;
+ if (!Op.getExpr()->evaluateAsAbsolute(Addr))
+ report_fatal_error("Unsupported asm expression. Only absolute address "
+ "can be placed here.");
+ Value |= static_cast<uint64_t>(Addr);
} else {
llvm_unreachable("Unsupported operand type");
}
diff --git a/llvm/test/MC/M68k/pc-rel.s b/llvm/test/MC/M68k/pc-rel.s
new file mode 100644
index 0000000000000..a4d76d341bb05
--- /dev/null
+++ b/llvm/test/MC/M68k/pc-rel.s
@@ -0,0 +1,22 @@
+; RUN: llvm-mc -triple=m68k -show-encoding %s | FileCheck %s
+
+ ; A fixup whose size is multiple of a word.
+ ; CHECK: cmpi.l #87, (.LBB0_1,%pc)
+ ; CHECK-SAME: encoding: [0x0c,0xba,0x00,0x00,0x00,0x57,A,A]
+ ; CHECK: fixup A - offset: 6, value: .LBB0_1, kind: FK_PCRel_2
+ cmpi.l #87, (.LBB0_1,%pc)
+
+ ; A fixup that is smaller than a word.
+ ; For cases where the fixup is located in the first word, they are
+ ; tested by `Control/branch-pc-rel.s`.
+ ; CHECK: cmpi.l #94, (.LBB0_2,%pc,%a0)
+ ; CHECK-SAME: encoding: [0x0c,0xbb,0x00,0x00,0x00,0x5e,0x88,A]
+ ; CHECK: fixup A - offset: 7, value: .LBB0_2+1, kind: FK_PCRel_1
+ cmpi.l #94, (.LBB0_2,%pc,%a0)
+.LBB0_1:
+ add.l #0, %d0
+ rts
+.LBB0_2:
+ add.l #1, %d0
+ rts
+
More information about the llvm-commits
mailing list