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
|
@ -243,7 +243,8 @@ def MxEncEAk : MxEncEA<MxBead3Bits<0b011>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
|
||||||
def MxEncEAi : MxEncEA<MxBead3Bits<0b100>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
|
def MxEncEAi : MxEncEA<MxBead3Bits<0b100>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
|
||||||
|
|
||||||
class MxEncBriefExt<string reg_opnd, string disp_opnd,
|
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
|
dag Value = (descend
|
||||||
// D/A + REGISTER
|
// D/A + REGISTER
|
||||||
(operand "$"#reg_opnd, 4),
|
(operand "$"#reg_opnd, 4),
|
||||||
|
@ -258,16 +259,22 @@ class MxEncBriefExt<string reg_opnd, string disp_opnd,
|
||||||
),
|
),
|
||||||
0b0,
|
0b0,
|
||||||
// Displacement
|
// 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 {
|
class MxEncAddrMode_k<string opnd_name> : MxEncMemOp {
|
||||||
let EA = (descend /*MODE*/0b111,
|
let EA = (descend /*MODE*/0b111,
|
||||||
/*REGISTER*/0b011);
|
/*REGISTER*/0b011);
|
||||||
|
|
||||||
let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
|
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 {
|
class MxEncAddrMode_q<string opnd_name> : MxEncMemOp {
|
||||||
|
@ -275,7 +282,8 @@ class MxEncAddrMode_q<string opnd_name> : MxEncMemOp {
|
||||||
/*REGISTER*/0b010);
|
/*REGISTER*/0b010);
|
||||||
|
|
||||||
// 16-bit Displacement
|
// 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 {
|
class MxEncAddrMode_p<string opnd_name> : MxEncMemOp {
|
||||||
|
@ -283,7 +291,8 @@ class MxEncAddrMode_p<string opnd_name> : MxEncMemOp {
|
||||||
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
|
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
|
||||||
|
|
||||||
// 16-bit Displacement
|
// 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 {
|
class MxEncAddrMode_f<string opnd_name> : MxEncMemOp {
|
||||||
|
@ -291,7 +300,8 @@ class MxEncAddrMode_f<string opnd_name> : MxEncMemOp {
|
||||||
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
|
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));
|
||||||
|
|
||||||
let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
|
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 {
|
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
|
// Absolute address
|
||||||
let Supplement = !if(size_w_l,
|
let Supplement = !if(size_w_l,
|
||||||
// abs.L
|
// abs.L
|
||||||
(ascend (slice "$"#opnd_name, 31, 16),
|
(operand "$"#opnd_name, 32, (encoder "encodeRelocImm<32>")),
|
||||||
(slice "$"#opnd_name, 15, 0)),
|
|
||||||
// abs.W
|
// 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/Debug.h"
|
||||||
#include "llvm/Support/EndianStream.h"
|
#include "llvm/Support/EndianStream.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
@ -48,6 +49,16 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
|
||||||
SmallVectorImpl<MCFixup> &Fixups,
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
const MCSubtargetInfo &STI) const;
|
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:
|
public:
|
||||||
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
|
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
|
||||||
: MCII(mcii), Ctx(ctx) {}
|
: MCII(mcii), Ctx(ctx) {}
|
||||||
|
@ -83,6 +94,122 @@ public:
|
||||||
|
|
||||||
#include "M68kGenMCCodeEmitter.inc"
|
#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,
|
void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
|
||||||
unsigned InsertPos, APInt &Value,
|
unsigned InsertPos, APInt &Value,
|
||||||
SmallVectorImpl<MCFixup> &Fixups,
|
SmallVectorImpl<MCFixup> &Fixups,
|
||||||
|
@ -98,6 +225,13 @@ void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
|
||||||
} else if (Op.isImm()) {
|
} else if (Op.isImm()) {
|
||||||
// Immediate
|
// Immediate
|
||||||
Value |= static_cast<uint64_t>(Op.getImm());
|
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 {
|
} else {
|
||||||
llvm_unreachable("Unsupported operand type");
|
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