[llvm-dev] Printing PC-relative offsets - how to get the instruction length?
Mark R V Murray via llvm-dev
llvm-dev at lists.llvm.org
Mon Mar 25 09:18:59 PDT 2019
Hi
In my MC6809 backend, in llvm/lib/Target/MC6809/InstPrinter/MC6809InstPrinter.cpp, I have the routine
void MC6809InstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
ZZ
if (Op.isImm()) {
int64_t Imm = Op.getImm() + 2; <<<========================
O << "$";
if (Imm >= 0)
O << '+';
O << Imm;
} else {
assert(Op.isExpr() && "unknown pcrel immediate operand");
Op.getExpr()->print(O, &MAI);
}
}
Which works well enough except for the constant 2 that I've arrowed - it needs to be the length of the binary instruction in bytes. The MC6809 has a *LOT* of variability here, so a case statement would be a right pain to maintain.
An answer is tantalisingly close:
$ bin/llvm-mc -triple mc6809 -show-inst-operands -show-inst -show-encoding <<< "lda 0,pc"
.text
<stdin>:1:1: note: parsed instruction: ['lda', 0, <register 13>]
lda 0,pc
^
lda $+2,pc ; encoding: [0xa6,0x8c,0x00] <<===========
; <MCInst #1849 LDAi8oPC
; <MCOperand Imm:0>
; <MCOperand Imm:0>>
The "encoding:" knows that I have a three-byte instruction, but that is generated by another chunk of code miles away. I suppose I could replicate that, but it seems wasteful. Is there a better way, not involving nasty layering violations, to get the length of an instruction in bytes in the context of llvm/lib/Target/*/InstPrinter/*InstPrinter.cpp?
Also, both 8 and 16-bit variants are possible. The instruction picked is LDAi8oPC with is the 8-bit offset version. If I supply a bigger offset:
$ bin/llvm-mc -triple mc6809 -show-inst-operands -show-inst -show-encoding <<< "lda 1000,pc"
.text
<stdin>:1:1: note: parsed instruction: ['lda', 1000, <register 13>]
lda 1000,pc
^
lda $+1002,pc ; encoding: [0xa6,0x8c,0xe8]
; <MCInst #1849 LDAi8oPC
; <MCOperand Imm:0>
; <MCOperand Imm:1000>>
I still get the 8-bit variant instead of LDAi16oPC, and the operand is truncated.
The TableGen-generated .inc file has
{ 444 /* lda */, MC6809::LDAi8oPC, Convert__imm_95_0__Imm81_0, AMFBS_None, { MCK_Imm8, MCK_PC }, },
{ 444 /* lda */, MC6809::LDAi16oPC, Convert__imm_95_0__Imm161_0, AMFBS_None, { MCK_Imm16, MCK_PC }, },
... so how do I get the 16-bit variant with MCK_Imm16 selected instead?
The instructions are defined as
def LDAi8oPC : MC6809LoadIndexed_i8oPC_P1<
(outs GR8:$dst8),
(ins pcoffset8:$offset),
!strconcat("lda", "\t", "${offset}", ",", "pc"),
0x00,
0xA6,
[]
> { let Inst{23-16} = offset{7-0}; let Inst{15} = 0b1; let Inst{14-13} = 0b00; let Inst{12-8} = 0b01100; let Inst{7-0} = opcode; }
def LDAi16oPC : MC6809LoadIndexed_i16oPC_P1<
(outs GR8:$dst8),
(ins pcoffset16:$offset),
!strconcat("lda", "\t", "${offset}", ",", "pc"),
0x00,
0xA6,
[]
> { let Inst{31-24} = offset{7-0}; let Inst{23-16} = offset{15-8}; let Inst{15} = 0b1; let Inst{14-13} = 0b00; let Inst{12-8} = 0b01101; let Inst{7-0} = opcode; }
and I have
def pcoffset8 : Operand<i8>, ImmLeaf<i8, [{ return Immediate >= -128 && Immediate <= 127; }]> {
let PrintMethod = "printPCRelImmOperand";
let MIOperandInfo = (ops i8imm);
let ParserMatchClass = ImmediateAsmOperand<"Imm8">;
let EncoderMethod = "getMemOpValue";
let DecoderMethod = "DecodeMemOperand";
}
def pcoffset16 : Operand<i16>, ImmLeaf<i16, [{ return Immediate >= -32768 && Immediate <= 32767; }]> {
let PrintMethod = "printPCRelImmOperand";
let MIOperandInfo = (ops i16imm);
let ParserMatchClass = ImmediateAsmOperand<"Imm16">;
let EncoderMethod = "getMemOpValue";
let DecoderMethod = "DecodeMemOperand";
}
M
--
Mark R V Murray
More information about the llvm-dev
mailing list