xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This class prints an ARC MCInst to a .s file.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARCInstPrinter.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/ARCInfo.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
200b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
210b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #include "ARCGenAsmWriter.inc"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric template <class T>
BadConditionCode(T cc)310b57cec5SDimitry Andric static const char *BadConditionCode(T cc) {
320b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Unknown condition code passed: " << cc << "\n");
330b57cec5SDimitry Andric   return "{unknown-cc}";
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
ARCBRCondCodeToString(ARCCC::BRCondCode BRCC)360b57cec5SDimitry Andric static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) {
370b57cec5SDimitry Andric   switch (BRCC) {
380b57cec5SDimitry Andric   case ARCCC::BREQ:
390b57cec5SDimitry Andric     return "eq";
400b57cec5SDimitry Andric   case ARCCC::BRNE:
410b57cec5SDimitry Andric     return "ne";
420b57cec5SDimitry Andric   case ARCCC::BRLT:
430b57cec5SDimitry Andric     return "lt";
440b57cec5SDimitry Andric   case ARCCC::BRGE:
450b57cec5SDimitry Andric     return "ge";
460b57cec5SDimitry Andric   case ARCCC::BRLO:
470b57cec5SDimitry Andric     return "lo";
480b57cec5SDimitry Andric   case ARCCC::BRHS:
490b57cec5SDimitry Andric     return "hs";
500b57cec5SDimitry Andric   }
510b57cec5SDimitry Andric   return BadConditionCode(BRCC);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
ARCCondCodeToString(ARCCC::CondCode CC)540b57cec5SDimitry Andric static const char *ARCCondCodeToString(ARCCC::CondCode CC) {
550b57cec5SDimitry Andric   switch (CC) {
560b57cec5SDimitry Andric   case ARCCC::EQ:
570b57cec5SDimitry Andric     return "eq";
580b57cec5SDimitry Andric   case ARCCC::NE:
590b57cec5SDimitry Andric     return "ne";
600b57cec5SDimitry Andric   case ARCCC::P:
610b57cec5SDimitry Andric     return "p";
620b57cec5SDimitry Andric   case ARCCC::N:
630b57cec5SDimitry Andric     return "n";
640b57cec5SDimitry Andric   case ARCCC::HS:
650b57cec5SDimitry Andric     return "hs";
660b57cec5SDimitry Andric   case ARCCC::LO:
670b57cec5SDimitry Andric     return "lo";
680b57cec5SDimitry Andric   case ARCCC::GT:
690b57cec5SDimitry Andric     return "gt";
700b57cec5SDimitry Andric   case ARCCC::GE:
710b57cec5SDimitry Andric     return "ge";
720b57cec5SDimitry Andric   case ARCCC::VS:
730b57cec5SDimitry Andric     return "vs";
740b57cec5SDimitry Andric   case ARCCC::VC:
750b57cec5SDimitry Andric     return "vc";
760b57cec5SDimitry Andric   case ARCCC::LT:
770b57cec5SDimitry Andric     return "lt";
780b57cec5SDimitry Andric   case ARCCC::LE:
790b57cec5SDimitry Andric     return "le";
800b57cec5SDimitry Andric   case ARCCC::HI:
810b57cec5SDimitry Andric     return "hi";
820b57cec5SDimitry Andric   case ARCCC::LS:
830b57cec5SDimitry Andric     return "ls";
840b57cec5SDimitry Andric   case ARCCC::PNZ:
850b57cec5SDimitry Andric     return "pnz";
860b57cec5SDimitry Andric   case ARCCC::AL:
870b57cec5SDimitry Andric     return "al";
880b57cec5SDimitry Andric   case ARCCC::NZ:
890b57cec5SDimitry Andric     return "nz";
900b57cec5SDimitry Andric   case ARCCC::Z:
910b57cec5SDimitry Andric     return "z";
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric   return BadConditionCode(CC);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
printRegName(raw_ostream & OS,MCRegister Reg) const96*bdd1243dSDimitry Andric void ARCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {
97*bdd1243dSDimitry Andric   OS << StringRef(getRegisterName(Reg)).lower();
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)100480093f4SDimitry Andric void ARCInstPrinter::printInst(const MCInst *MI, uint64_t Address,
101480093f4SDimitry Andric                                StringRef Annot, const MCSubtargetInfo &STI,
102480093f4SDimitry Andric                                raw_ostream &O) {
103480093f4SDimitry Andric   printInstruction(MI, Address, O);
1040b57cec5SDimitry Andric   printAnnotation(O, Annot);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
printExpr(const MCExpr * Expr,const MCAsmInfo * MAI,raw_ostream & OS)1070b57cec5SDimitry Andric static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI,
1080b57cec5SDimitry Andric                       raw_ostream &OS) {
1090b57cec5SDimitry Andric   int Offset = 0;
1100b57cec5SDimitry Andric   const MCSymbolRefExpr *SRE;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   if (const auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
1130b57cec5SDimitry Andric     OS << "0x";
1140b57cec5SDimitry Andric     OS.write_hex(CE->getValue());
1150b57cec5SDimitry Andric     return;
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) {
1190b57cec5SDimitry Andric     SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
1200b57cec5SDimitry Andric     const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
1210b57cec5SDimitry Andric     assert(SRE && CE && "Binary expression must be sym+const.");
1220b57cec5SDimitry Andric     Offset = CE->getValue();
1230b57cec5SDimitry Andric   } else {
1240b57cec5SDimitry Andric     SRE = dyn_cast<MCSymbolRefExpr>(Expr);
1250b57cec5SDimitry Andric     assert(SRE && "Unexpected MCExpr type.");
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric   assert(SRE->getKind() == MCSymbolRefExpr::VK_None);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   // Symbols are prefixed with '@'
1300b57cec5SDimitry Andric   OS << '@';
1310b57cec5SDimitry Andric   SRE->getSymbol().print(OS, MAI);
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (Offset) {
1340b57cec5SDimitry Andric     if (Offset > 0)
1350b57cec5SDimitry Andric       OS << '+';
1360b57cec5SDimitry Andric     OS << Offset;
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
printOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)1400b57cec5SDimitry Andric void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum,
1410b57cec5SDimitry Andric                                   raw_ostream &O) {
1420b57cec5SDimitry Andric   const MCOperand &Op = MI->getOperand(OpNum);
1430b57cec5SDimitry Andric   if (Op.isReg()) {
1440b57cec5SDimitry Andric     printRegName(O, Op.getReg());
1450b57cec5SDimitry Andric     return;
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   if (Op.isImm()) {
1490b57cec5SDimitry Andric     O << Op.getImm();
1500b57cec5SDimitry Andric     return;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   assert(Op.isExpr() && "unknown operand kind in printOperand");
1540b57cec5SDimitry Andric   printExpr(Op.getExpr(), &MAI, O);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
printMemOperandRI(const MCInst * MI,unsigned OpNum,raw_ostream & O)1570b57cec5SDimitry Andric void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum,
1580b57cec5SDimitry Andric                                        raw_ostream &O) {
1590b57cec5SDimitry Andric   const MCOperand &base = MI->getOperand(OpNum);
1600b57cec5SDimitry Andric   const MCOperand &offset = MI->getOperand(OpNum + 1);
1610b57cec5SDimitry Andric   assert(base.isReg() && "Base should be register.");
1620b57cec5SDimitry Andric   assert(offset.isImm() && "Offset should be immediate.");
1630b57cec5SDimitry Andric   printRegName(O, base.getReg());
1640b57cec5SDimitry Andric   O << "," << offset.getImm();
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
printPredicateOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)1670b57cec5SDimitry Andric void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum,
1680b57cec5SDimitry Andric                                            raw_ostream &O) {
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   const MCOperand &Op = MI->getOperand(OpNum);
1710b57cec5SDimitry Andric   assert(Op.isImm() && "Predicate operand is immediate.");
1720b57cec5SDimitry Andric   O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm());
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
printBRCCPredicateOperand(const MCInst * MI,unsigned OpNum,raw_ostream & O)1750b57cec5SDimitry Andric void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum,
1760b57cec5SDimitry Andric                                                raw_ostream &O) {
1770b57cec5SDimitry Andric   const MCOperand &Op = MI->getOperand(OpNum);
1780b57cec5SDimitry Andric   assert(Op.isImm() && "Predicate operand is immediate.");
1790b57cec5SDimitry Andric   O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm());
1800b57cec5SDimitry Andric }
181fe6060f1SDimitry Andric 
printCCOperand(const MCInst * MI,int OpNum,raw_ostream & O)182fe6060f1SDimitry Andric void ARCInstPrinter::printCCOperand(const MCInst *MI, int OpNum,
183fe6060f1SDimitry Andric                                     raw_ostream &O) {
184fe6060f1SDimitry Andric   O << ARCCondCodeToString((ARCCC::CondCode)MI->getOperand(OpNum).getImm());
185fe6060f1SDimitry Andric }
186fe6060f1SDimitry Andric 
printU6ShiftedBy(unsigned ShiftBy,const MCInst * MI,int OpNum,raw_ostream & O)187fe6060f1SDimitry Andric void ARCInstPrinter::printU6ShiftedBy(unsigned ShiftBy, const MCInst *MI,
188fe6060f1SDimitry Andric                                       int OpNum, raw_ostream &O) {
189fe6060f1SDimitry Andric   const MCOperand &MO = MI->getOperand(OpNum);
190fe6060f1SDimitry Andric   if (MO.isImm()) {
191fe6060f1SDimitry Andric     unsigned Value = MO.getImm();
192fe6060f1SDimitry Andric     unsigned Value2 = Value >> ShiftBy;
193fe6060f1SDimitry Andric     if (Value2 > 0x3F || (Value2 << ShiftBy != Value)) {
194fe6060f1SDimitry Andric       errs() << "!!! Instruction has out-of-range U6 immediate operand:\n"
195fe6060f1SDimitry Andric              << "    Opcode is " << MI->getOpcode() << "; operand value is "
196fe6060f1SDimitry Andric              << Value;
197fe6060f1SDimitry Andric       if (ShiftBy)
198fe6060f1SDimitry Andric         errs() << " scaled by " << (1 << ShiftBy) << "\n";
199fe6060f1SDimitry Andric       assert(false && "instruction has wrong format");
200fe6060f1SDimitry Andric     }
201fe6060f1SDimitry Andric   }
202fe6060f1SDimitry Andric   printOperand(MI, OpNum, O);
203fe6060f1SDimitry Andric }
204fe6060f1SDimitry Andric 
printU6(const MCInst * MI,int OpNum,raw_ostream & O)205fe6060f1SDimitry Andric void ARCInstPrinter::printU6(const MCInst *MI, int OpNum, raw_ostream &O) {
206fe6060f1SDimitry Andric   printU6ShiftedBy(0, MI, OpNum, O);
207fe6060f1SDimitry Andric }
208