| //===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===// | |
| // | |
| // 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 ARC MCInst to a .s file. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "ARCInstPrinter.h" | |
| #include "MCTargetDesc/ARCInfo.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstrInfo.h" | |
| #include "llvm/MC/MCSymbol.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "asm-printer" | |
| #include "ARCGenAsmWriter.inc" | |
| static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) { | |
| switch (BRCC) { | |
| case ARCCC::BREQ: | |
| return "eq"; | |
| case ARCCC::BRNE: | |
| return "ne"; | |
| case ARCCC::BRLT: | |
| return "lt"; | |
| case ARCCC::BRGE: | |
| return "ge"; | |
| case ARCCC::BRLO: | |
| return "lo"; | |
| case ARCCC::BRHS: | |
| return "hs"; | |
| } | |
| llvm_unreachable("Unhandled ARCCC::BRCondCode"); | |
| } | |
| static const char *ARCCondCodeToString(ARCCC::CondCode CC) { | |
| switch (CC) { | |
| case ARCCC::EQ: | |
| return "eq"; | |
| case ARCCC::NE: | |
| return "ne"; | |
| case ARCCC::P: | |
| return "p"; | |
| case ARCCC::N: | |
| return "n"; | |
| case ARCCC::HS: | |
| return "hs"; | |
| case ARCCC::LO: | |
| return "lo"; | |
| case ARCCC::GT: | |
| return "gt"; | |
| case ARCCC::GE: | |
| return "ge"; | |
| case ARCCC::VS: | |
| return "vs"; | |
| case ARCCC::VC: | |
| return "vc"; | |
| case ARCCC::LT: | |
| return "lt"; | |
| case ARCCC::LE: | |
| return "le"; | |
| case ARCCC::HI: | |
| return "hi"; | |
| case ARCCC::LS: | |
| return "ls"; | |
| case ARCCC::PNZ: | |
| return "pnz"; | |
| case ARCCC::AL: | |
| return "al"; | |
| case ARCCC::NZ: | |
| return "nz"; | |
| case ARCCC::Z: | |
| return "z"; | |
| } | |
| llvm_unreachable("Unhandled ARCCC::CondCode"); | |
| } | |
| void ARCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { | |
| OS << StringRef(getRegisterName(RegNo)).lower(); | |
| } | |
| void ARCInstPrinter::printInst(const MCInst *MI, raw_ostream &O, | |
| StringRef Annot, const MCSubtargetInfo &STI) { | |
| printInstruction(MI, O); | |
| printAnnotation(O, Annot); | |
| } | |
| static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI, | |
| raw_ostream &OS) { | |
| int Offset = 0; | |
| const MCSymbolRefExpr *SRE; | |
| if (const auto *CE = dyn_cast<MCConstantExpr>(Expr)) { | |
| OS << "0x"; | |
| OS.write_hex(CE->getValue()); | |
| return; | |
| } | |
| if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) { | |
| SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); | |
| const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); | |
| assert(SRE && CE && "Binary expression must be sym+const."); | |
| Offset = CE->getValue(); | |
| } else { | |
| SRE = dyn_cast<MCSymbolRefExpr>(Expr); | |
| assert(SRE && "Unexpected MCExpr type."); | |
| } | |
| assert(SRE->getKind() == MCSymbolRefExpr::VK_None); | |
| // Symbols are prefixed with '@' | |
| OS << '@'; | |
| SRE->getSymbol().print(OS, MAI); | |
| if (Offset) { | |
| if (Offset > 0) | |
| OS << '+'; | |
| OS << Offset; | |
| } | |
| } | |
| void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum, | |
| raw_ostream &O) { | |
| const MCOperand &Op = MI->getOperand(OpNum); | |
| if (Op.isReg()) { | |
| printRegName(O, Op.getReg()); | |
| return; | |
| } | |
| if (Op.isImm()) { | |
| O << Op.getImm(); | |
| return; | |
| } | |
| assert(Op.isExpr() && "unknown operand kind in printOperand"); | |
| printExpr(Op.getExpr(), &MAI, O); | |
| } | |
| void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum, | |
| raw_ostream &O) { | |
| const MCOperand &base = MI->getOperand(OpNum); | |
| const MCOperand &offset = MI->getOperand(OpNum + 1); | |
| assert(base.isReg() && "Base should be register."); | |
| assert(offset.isImm() && "Offset should be immediate."); | |
| printRegName(O, base.getReg()); | |
| O << "," << offset.getImm(); | |
| } | |
| void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum, | |
| raw_ostream &O) { | |
| const MCOperand &Op = MI->getOperand(OpNum); | |
| assert(Op.isImm() && "Predicate operand is immediate."); | |
| O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm()); | |
| } | |
| void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum, | |
| raw_ostream &O) { | |
| const MCOperand &Op = MI->getOperand(OpNum); | |
| assert(Op.isImm() && "Predicate operand is immediate."); | |
| O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm()); | |
| } |