208 lines · cpp
1//===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class prints an ARC MCInst to a .s file.10//11//===----------------------------------------------------------------------===//12 13#include "ARCInstPrinter.h"14#include "MCTargetDesc/ARCInfo.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/MC/MCExpr.h"17#include "llvm/MC/MCInst.h"18#include "llvm/MC/MCInstrInfo.h"19#include "llvm/MC/MCSymbol.h"20#include "llvm/Support/Casting.h"21#include "llvm/Support/Debug.h"22#include "llvm/Support/raw_ostream.h"23 24using namespace llvm;25 26#define DEBUG_TYPE "asm-printer"27 28#include "ARCGenAsmWriter.inc"29 30template <class T>31static const char *BadConditionCode(T cc) {32 LLVM_DEBUG(dbgs() << "Unknown condition code passed: " << cc << "\n");33 return "{unknown-cc}";34}35 36static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) {37 switch (BRCC) {38 case ARCCC::BREQ:39 return "eq";40 case ARCCC::BRNE:41 return "ne";42 case ARCCC::BRLT:43 return "lt";44 case ARCCC::BRGE:45 return "ge";46 case ARCCC::BRLO:47 return "lo";48 case ARCCC::BRHS:49 return "hs";50 }51 return BadConditionCode(BRCC);52}53 54static const char *ARCCondCodeToString(ARCCC::CondCode CC) {55 switch (CC) {56 case ARCCC::EQ:57 return "eq";58 case ARCCC::NE:59 return "ne";60 case ARCCC::P:61 return "p";62 case ARCCC::N:63 return "n";64 case ARCCC::HS:65 return "hs";66 case ARCCC::LO:67 return "lo";68 case ARCCC::GT:69 return "gt";70 case ARCCC::GE:71 return "ge";72 case ARCCC::VS:73 return "vs";74 case ARCCC::VC:75 return "vc";76 case ARCCC::LT:77 return "lt";78 case ARCCC::LE:79 return "le";80 case ARCCC::HI:81 return "hi";82 case ARCCC::LS:83 return "ls";84 case ARCCC::PNZ:85 return "pnz";86 case ARCCC::AL:87 return "al";88 case ARCCC::NZ:89 return "nz";90 case ARCCC::Z:91 return "z";92 }93 return BadConditionCode(CC);94}95 96void ARCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) {97 OS << StringRef(getRegisterName(Reg)).lower();98}99 100void ARCInstPrinter::printInst(const MCInst *MI, uint64_t Address,101 StringRef Annot, const MCSubtargetInfo &STI,102 raw_ostream &O) {103 printInstruction(MI, Address, O);104 printAnnotation(O, Annot);105}106 107static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI,108 raw_ostream &OS) {109 int Offset = 0;110 const MCSymbolRefExpr *SRE;111 112 if (const auto *CE = dyn_cast<MCConstantExpr>(Expr)) {113 OS << "0x";114 OS.write_hex(CE->getValue());115 return;116 }117 118 if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) {119 SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());120 const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS());121 assert(SRE && CE && "Binary expression must be sym+const.");122 Offset = CE->getValue();123 } else {124 SRE = dyn_cast<MCSymbolRefExpr>(Expr);125 assert(SRE && "Unexpected MCExpr type.");126 }127 assert(SRE->getSpecifier() == 0);128 129 // Symbols are prefixed with '@'130 OS << '@';131 SRE->getSymbol().print(OS, MAI);132 133 if (Offset) {134 if (Offset > 0)135 OS << '+';136 OS << Offset;137 }138}139 140void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum,141 raw_ostream &O) {142 const MCOperand &Op = MI->getOperand(OpNum);143 if (Op.isReg()) {144 printRegName(O, Op.getReg());145 return;146 }147 148 if (Op.isImm()) {149 O << Op.getImm();150 return;151 }152 153 assert(Op.isExpr() && "unknown operand kind in printOperand");154 printExpr(Op.getExpr(), &MAI, O);155}156 157void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum,158 raw_ostream &O) {159 const MCOperand &base = MI->getOperand(OpNum);160 const MCOperand &offset = MI->getOperand(OpNum + 1);161 assert(base.isReg() && "Base should be register.");162 assert(offset.isImm() && "Offset should be immediate.");163 printRegName(O, base.getReg());164 O << "," << offset.getImm();165}166 167void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum,168 raw_ostream &O) {169 170 const MCOperand &Op = MI->getOperand(OpNum);171 assert(Op.isImm() && "Predicate operand is immediate.");172 O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm());173}174 175void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum,176 raw_ostream &O) {177 const MCOperand &Op = MI->getOperand(OpNum);178 assert(Op.isImm() && "Predicate operand is immediate.");179 O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm());180}181 182void ARCInstPrinter::printCCOperand(const MCInst *MI, int OpNum,183 raw_ostream &O) {184 O << ARCCondCodeToString((ARCCC::CondCode)MI->getOperand(OpNum).getImm());185}186 187void ARCInstPrinter::printU6ShiftedBy(unsigned ShiftBy, const MCInst *MI,188 int OpNum, raw_ostream &O) {189 const MCOperand &MO = MI->getOperand(OpNum);190 if (MO.isImm()) {191 unsigned Value = MO.getImm();192 unsigned Value2 = Value >> ShiftBy;193 if (Value2 > 0x3F || (Value2 << ShiftBy != Value)) {194 errs() << "!!! Instruction has out-of-range U6 immediate operand:\n"195 << " Opcode is " << MI->getOpcode() << "; operand value is "196 << Value;197 if (ShiftBy)198 errs() << " scaled by " << (1 << ShiftBy) << "\n";199 assert(false && "instruction has wrong format");200 }201 }202 printOperand(MI, OpNum, O);203}204 205void ARCInstPrinter::printU6(const MCInst *MI, int OpNum, raw_ostream &O) {206 printU6ShiftedBy(0, MI, OpNum, O);207}208