1 //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a printer that converts from our internal representation 10 // of machine-dependent LLVM code to the RISCV assembly language. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "RISCV.h" 15 #include "MCTargetDesc/RISCVInstPrinter.h" 16 #include "MCTargetDesc/RISCVMCExpr.h" 17 #include "RISCVTargetMachine.h" 18 #include "TargetInfo/RISCVTargetInfo.h" 19 #include "llvm/ADT/Statistic.h" 20 #include "llvm/CodeGen/AsmPrinter.h" 21 #include "llvm/CodeGen/MachineConstantPool.h" 22 #include "llvm/CodeGen/MachineFunctionPass.h" 23 #include "llvm/CodeGen/MachineInstr.h" 24 #include "llvm/CodeGen/MachineModuleInfo.h" 25 #include "llvm/MC/MCAsmInfo.h" 26 #include "llvm/MC/MCInst.h" 27 #include "llvm/MC/MCStreamer.h" 28 #include "llvm/MC/MCSymbol.h" 29 #include "llvm/Support/TargetRegistry.h" 30 #include "llvm/Support/raw_ostream.h" 31 using namespace llvm; 32 33 #define DEBUG_TYPE "asm-printer" 34 35 STATISTIC(RISCVNumInstrsCompressed, 36 "Number of RISC-V Compressed instructions emitted"); 37 38 namespace { 39 class RISCVAsmPrinter : public AsmPrinter { 40 const MCSubtargetInfo *STI; 41 42 public: 43 explicit RISCVAsmPrinter(TargetMachine &TM, 44 std::unique_ptr<MCStreamer> Streamer) 45 : AsmPrinter(TM, std::move(Streamer)), STI(TM.getMCSubtargetInfo()) {} 46 47 StringRef getPassName() const override { return "RISCV Assembly Printer"; } 48 49 bool runOnMachineFunction(MachineFunction &MF) override; 50 51 void emitInstruction(const MachineInstr *MI) override; 52 53 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 54 const char *ExtraCode, raw_ostream &OS) override; 55 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 56 const char *ExtraCode, raw_ostream &OS) override; 57 58 void EmitToStreamer(MCStreamer &S, const MCInst &Inst); 59 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, 60 const MachineInstr *MI); 61 62 // Wrapper needed for tblgenned pseudo lowering. 63 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { 64 return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this); 65 } 66 }; 67 } 68 69 #define GEN_COMPRESS_INSTR 70 #include "RISCVGenCompressInstEmitter.inc" 71 void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { 72 MCInst CInst; 73 bool Res = compressInst(CInst, Inst, *STI, OutStreamer->getContext()); 74 if (Res) 75 ++RISCVNumInstrsCompressed; 76 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); 77 } 78 79 // Simple pseudo-instructions have their lowering (with expansion to real 80 // instructions) auto-generated. 81 #include "RISCVGenMCPseudoLowering.inc" 82 83 void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) { 84 // Do any auto-generated pseudo lowerings. 85 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 86 return; 87 88 MCInst TmpInst; 89 LowerRISCVMachineInstrToMCInst(MI, TmpInst, *this); 90 EmitToStreamer(*OutStreamer, TmpInst); 91 } 92 93 bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 94 const char *ExtraCode, raw_ostream &OS) { 95 // First try the generic code, which knows about modifiers like 'c' and 'n'. 96 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 97 return false; 98 99 const MachineOperand &MO = MI->getOperand(OpNo); 100 if (ExtraCode && ExtraCode[0]) { 101 if (ExtraCode[1] != 0) 102 return true; // Unknown modifier. 103 104 switch (ExtraCode[0]) { 105 default: 106 return true; // Unknown modifier. 107 case 'z': // Print zero register if zero, regular printing otherwise. 108 if (MO.isImm() && MO.getImm() == 0) { 109 OS << RISCVInstPrinter::getRegisterName(RISCV::X0); 110 return false; 111 } 112 break; 113 case 'i': // Literal 'i' if operand is not a register. 114 if (!MO.isReg()) 115 OS << 'i'; 116 return false; 117 } 118 } 119 120 switch (MO.getType()) { 121 case MachineOperand::MO_Immediate: 122 OS << MO.getImm(); 123 return false; 124 case MachineOperand::MO_Register: 125 OS << RISCVInstPrinter::getRegisterName(MO.getReg()); 126 return false; 127 case MachineOperand::MO_GlobalAddress: 128 PrintSymbolOperand(MO, OS); 129 return false; 130 case MachineOperand::MO_BlockAddress: { 131 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); 132 Sym->print(OS, MAI); 133 return false; 134 } 135 default: 136 break; 137 } 138 139 return true; 140 } 141 142 bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 143 unsigned OpNo, 144 const char *ExtraCode, 145 raw_ostream &OS) { 146 if (!ExtraCode) { 147 const MachineOperand &MO = MI->getOperand(OpNo); 148 // For now, we only support register memory operands in registers and 149 // assume there is no addend 150 if (!MO.isReg()) 151 return true; 152 153 OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")"; 154 return false; 155 } 156 157 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 158 } 159 160 bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 161 // Set the current MCSubtargetInfo to a copy which has the correct 162 // feature bits for the current MachineFunction 163 MCSubtargetInfo &NewSTI = 164 OutStreamer->getContext().getSubtargetCopy(*TM.getMCSubtargetInfo()); 165 NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits()); 166 STI = &NewSTI; 167 168 SetupMachineFunction(MF); 169 emitFunctionBody(); 170 return false; 171 } 172 173 // Force static initialization. 174 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { 175 RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target()); 176 RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target()); 177 } 178