forked from OSchip/llvm-project
[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
This commit is contained in:
parent
920146316d
commit
53a2bf8ac7
llvm
|
@ -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>"))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ public:
|
|||
|
||||
#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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue