mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-16 11:30:51 +00:00
f09378397e
per-function subtarget. Currently, code-gen passes the default or generic subtarget to the constructors of MCInstPrinter subclasses (see LLVMTargetMachine::addPassesToEmitFile), which enables some targets (AArch64, ARM, and X86) to change their instprinter's behavior based on the subtarget feature bits. Since the backend can now use different subtargets for each function, instprinter has to be changed to use the per-function subtarget rather than the default subtarget. This patch takes the first step towards enabling instprinter to change its behavior based on the per-function subtarget. It adds a bit "PassSubtarget" to AsmWriter which tells table-gen to pass a reference to MCSubtargetInfo to the various print methods table-gen auto-generates. I will follow up with changes to instprinters of AArch64, ARM, and X86. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233411 91177308-0d34-0410-b5e6-96231b3b80d8
251 lines
8.1 KiB
C++
251 lines
8.1 KiB
C++
//===- HexagonInstPrinter.cpp - Convert Hexagon MCInst to assembly syntax -===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This class prints an Hexagon MCInst to a .s file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "HexagonAsmPrinter.h"
|
|
#include "Hexagon.h"
|
|
#include "HexagonInstPrinter.h"
|
|
#include "MCTargetDesc/HexagonMCInstrInfo.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
#define GET_INSTRUCTION_NAME
|
|
#include "HexagonGenAsmWriter.inc"
|
|
|
|
const char HexagonInstPrinter::PacketPadding = '\t';
|
|
// Return the minimum value that a constant extendable operand can have
|
|
// without being extended.
|
|
static int getMinValue(uint64_t TSFlags) {
|
|
unsigned isSigned =
|
|
(TSFlags >> HexagonII::ExtentSignedPos) & HexagonII::ExtentSignedMask;
|
|
unsigned bits =
|
|
(TSFlags >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask;
|
|
|
|
if (isSigned)
|
|
return -1U << (bits - 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Return the maximum value that a constant extendable operand can have
|
|
// without being extended.
|
|
static int getMaxValue(uint64_t TSFlags) {
|
|
unsigned isSigned =
|
|
(TSFlags >> HexagonII::ExtentSignedPos) & HexagonII::ExtentSignedMask;
|
|
unsigned bits =
|
|
(TSFlags >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask;
|
|
|
|
if (isSigned)
|
|
return ~(-1U << (bits - 1));
|
|
|
|
return ~(-1U << bits);
|
|
}
|
|
|
|
// Return true if the instruction must be extended.
|
|
static bool isExtended(uint64_t TSFlags) {
|
|
return (TSFlags >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask;
|
|
}
|
|
|
|
// Currently just used in an assert statement
|
|
static bool isExtendable(uint64_t TSFlags) LLVM_ATTRIBUTE_UNUSED;
|
|
// Return true if the instruction may be extended based on the operand value.
|
|
static bool isExtendable(uint64_t TSFlags) {
|
|
return (TSFlags >> HexagonII::ExtendablePos) & HexagonII::ExtendableMask;
|
|
}
|
|
|
|
StringRef HexagonInstPrinter::getOpcodeName(unsigned Opcode) const {
|
|
return MII.getName(Opcode);
|
|
}
|
|
|
|
StringRef HexagonInstPrinter::getRegName(unsigned RegNo) const {
|
|
return getRegisterName(RegNo);
|
|
}
|
|
|
|
void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
|
|
StringRef Annot,
|
|
const MCSubtargetInfo &STI) {
|
|
const char startPacket = '{',
|
|
endPacket = '}';
|
|
// TODO: add outer HW loop when it's supported too.
|
|
if (MI->getOpcode() == Hexagon::ENDLOOP0) {
|
|
// Ending a harware loop is different from ending an regular packet.
|
|
assert(HexagonMCInstrInfo::isPacketEnd(*MI) && "Loop-end must also end the packet");
|
|
|
|
if (HexagonMCInstrInfo::isPacketBegin(*MI)) {
|
|
// There must be a packet to end a loop.
|
|
// FIXME: when shuffling is always run, this shouldn't be needed.
|
|
MCInst Nop;
|
|
StringRef NoAnnot;
|
|
|
|
Nop.setOpcode (Hexagon::A2_nop);
|
|
HexagonMCInstrInfo::setPacketBegin (Nop, HexagonMCInstrInfo::isPacketBegin(*MI));
|
|
printInst (&Nop, O, NoAnnot, STI);
|
|
}
|
|
|
|
// Close the packet.
|
|
if (HexagonMCInstrInfo::isPacketEnd(*MI))
|
|
O << PacketPadding << endPacket;
|
|
|
|
printInstruction(MI, O);
|
|
}
|
|
else {
|
|
// Prefix the insn opening the packet.
|
|
if (HexagonMCInstrInfo::isPacketBegin(*MI))
|
|
O << PacketPadding << startPacket << '\n';
|
|
|
|
printInstruction(MI, O);
|
|
|
|
// Suffix the insn closing the packet.
|
|
if (HexagonMCInstrInfo::isPacketEnd(*MI))
|
|
// Suffix the packet in a new line always, since the GNU assembler has
|
|
// issues with a closing brace on the same line as CONST{32,64}.
|
|
O << '\n' << PacketPadding << endPacket;
|
|
}
|
|
|
|
printAnnotation(O, Annot);
|
|
}
|
|
|
|
void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
const MCOperand& MO = MI->getOperand(OpNo);
|
|
|
|
if (MO.isReg()) {
|
|
O << getRegisterName(MO.getReg());
|
|
} else if(MO.isExpr()) {
|
|
O << *MO.getExpr();
|
|
} else if(MO.isImm()) {
|
|
printImmOperand(MI, OpNo, O);
|
|
} else {
|
|
llvm_unreachable("Unknown operand");
|
|
}
|
|
}
|
|
|
|
void HexagonInstPrinter::printImmOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
const MCOperand& MO = MI->getOperand(OpNo);
|
|
|
|
if(MO.isExpr()) {
|
|
O << *MO.getExpr();
|
|
} else if(MO.isImm()) {
|
|
O << MI->getOperand(OpNo).getImm();
|
|
} else {
|
|
llvm_unreachable("Unknown operand");
|
|
}
|
|
}
|
|
|
|
void HexagonInstPrinter::printExtOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
const MCOperand &MO = MI->getOperand(OpNo);
|
|
const MCInstrDesc &MII = getMII().get(MI->getOpcode());
|
|
|
|
assert((isExtendable(MII.TSFlags) || isExtended(MII.TSFlags)) &&
|
|
"Expecting an extendable operand");
|
|
|
|
if (MO.isExpr() || isExtended(MII.TSFlags)) {
|
|
O << "#";
|
|
} else if (MO.isImm()) {
|
|
int ImmValue = MO.getImm();
|
|
if (ImmValue < getMinValue(MII.TSFlags) ||
|
|
ImmValue > getMaxValue(MII.TSFlags))
|
|
O << "#";
|
|
}
|
|
printOperand(MI, OpNo, O);
|
|
}
|
|
|
|
void HexagonInstPrinter::printUnsignedImmOperand(const MCInst *MI,
|
|
unsigned OpNo, raw_ostream &O) const {
|
|
O << MI->getOperand(OpNo).getImm();
|
|
}
|
|
|
|
void HexagonInstPrinter::printNegImmOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
O << -MI->getOperand(OpNo).getImm();
|
|
}
|
|
|
|
void HexagonInstPrinter::printNOneImmOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
O << -1;
|
|
}
|
|
|
|
void HexagonInstPrinter::printMEMriOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
const MCOperand& MO0 = MI->getOperand(OpNo);
|
|
const MCOperand& MO1 = MI->getOperand(OpNo + 1);
|
|
|
|
O << getRegisterName(MO0.getReg());
|
|
O << " + #" << MO1.getImm();
|
|
}
|
|
|
|
void HexagonInstPrinter::printFrameIndexOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
const MCOperand& MO0 = MI->getOperand(OpNo);
|
|
const MCOperand& MO1 = MI->getOperand(OpNo + 1);
|
|
|
|
O << getRegisterName(MO0.getReg()) << ", #" << MO1.getImm();
|
|
}
|
|
|
|
void HexagonInstPrinter::printGlobalOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
assert(MI->getOperand(OpNo).isExpr() && "Expecting expression");
|
|
|
|
printOperand(MI, OpNo, O);
|
|
}
|
|
|
|
void HexagonInstPrinter::printJumpTable(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
assert(MI->getOperand(OpNo).isExpr() && "Expecting expression");
|
|
|
|
printOperand(MI, OpNo, O);
|
|
}
|
|
|
|
void HexagonInstPrinter::printConstantPool(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
assert(MI->getOperand(OpNo).isExpr() && "Expecting expression");
|
|
|
|
printOperand(MI, OpNo, O);
|
|
}
|
|
|
|
void HexagonInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
// Branches can take an immediate operand. This is used by the branch
|
|
// selection pass to print $+8, an eight byte displacement from the PC.
|
|
llvm_unreachable("Unknown branch operand.");
|
|
}
|
|
|
|
void HexagonInstPrinter::printCallOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
}
|
|
|
|
void HexagonInstPrinter::printAbsAddrOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
}
|
|
|
|
void HexagonInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) const {
|
|
}
|
|
|
|
void HexagonInstPrinter::printSymbol(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O, bool hi) const {
|
|
assert(MI->getOperand(OpNo).isImm() && "Unknown symbol operand");
|
|
|
|
O << '#' << (hi ? "HI" : "LO") << "(#";
|
|
printOperand(MI, OpNo, O);
|
|
O << ')';
|
|
}
|