1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
//===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class prints an AVR MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#include "AVRInstPrinter.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include <cstring>
#define DEBUG_TYPE "asm-printer"
namespace llvm {
// Include the auto-generated portion of the assembly writer.
#define PRINT_ALIAS_INSTR
#include "AVRGenAsmWriter.inc"
void AVRInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
unsigned Opcode = MI->getOpcode();
// First handle load and store instructions with postinc or predec
// of the form "ld reg, X+".
// TODO: We should be able to rewrite this using TableGen data.
switch (Opcode) {
case AVR::LDRdPtr:
case AVR::LDRdPtrPi:
case AVR::LDRdPtrPd:
O << "\tld\t";
printOperand(MI, 0, O);
O << ", ";
if (Opcode == AVR::LDRdPtrPd)
O << '-';
printOperand(MI, 1, O);
if (Opcode == AVR::LDRdPtrPi)
O << '+';
break;
case AVR::STPtrRr:
O << "\tst\t";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
break;
case AVR::STPtrPiRr:
case AVR::STPtrPdRr:
O << "\tst\t";
if (Opcode == AVR::STPtrPdRr)
O << '-';
printOperand(MI, 1, O);
if (Opcode == AVR::STPtrPiRr)
O << '+';
O << ", ";
printOperand(MI, 2, O);
break;
default:
if (!printAliasInstr(MI, O))
printInstruction(MI, O);
printAnnotation(O, Annot);
break;
}
}
const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
MCRegisterInfo const &MRI) {
// GCC prints register pairs by just printing the lower register
// If the register contains a subregister, print it instead
if (MRI.getNumSubRegIndices() > 0) {
unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
}
return getRegisterName(RegNum);
}
void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).OpInfo[OpNo];
if (Op.isReg()) {
bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
(MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
(MOI.RegClass == AVR::ZREGRegClassID);
if (isPtrReg) {
O << getRegisterName(Op.getReg(), AVR::ptr);
} else {
O << getPrettyRegisterName(Op.getReg(), MRI);
}
} else if (Op.isImm()) {
O << Op.getImm();
} else {
assert(Op.isExpr() && "Unknown operand kind in printOperand");
O << *Op.getExpr();
}
}
/// This is used to print an immediate value that ends up
/// being encoded as a pc-relative value.
void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
int64_t Imm = Op.getImm();
O << '.';
// Print a position sign if needed.
// Negative values have their sign printed automatically.
if (Imm >= 0)
O << '+';
O << Imm;
} else {
assert(Op.isExpr() && "Unknown pcrel immediate operand");
O << *Op.getExpr();
}
}
void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
assert(MI->getOperand(OpNo).isReg() && "Expected a register for the first operand");
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
// Print the register.
printOperand(MI, OpNo, O);
// Print the {+,-}offset.
if (OffsetOp.isImm()) {
int64_t Offset = OffsetOp.getImm();
if (Offset >= 0)
O << '+';
O << Offset;
} else if (OffsetOp.isExpr()) {
O << *OffsetOp.getExpr();
} else {
llvm_unreachable("unknown type for offset");
}
}
} // end of namespace llvm
|