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 "InstPrinter/RISCVInstPrinter.h"
16 #include "MCTargetDesc/RISCVMCExpr.h"
17 #include "RISCVTargetMachine.h"
18 #include "llvm/CodeGen/AsmPrinter.h"
19 #include "llvm/CodeGen/MachineConstantPool.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineModuleInfo.h"
23 #include "llvm/MC/MCAsmInfo.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/MC/MCStreamer.h"
26 #include "llvm/MC/MCSymbol.h"
27 #include "llvm/Support/TargetRegistry.h"
28 #include "llvm/Support/raw_ostream.h"
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "asm-printer"
32 
33 namespace {
34 class RISCVAsmPrinter : public AsmPrinter {
35 public:
36   explicit RISCVAsmPrinter(TargetMachine &TM,
37                            std::unique_ptr<MCStreamer> Streamer)
38       : AsmPrinter(TM, std::move(Streamer)) {}
39 
40   StringRef getPassName() const override { return "RISCV Assembly Printer"; }
41 
42   void EmitInstruction(const MachineInstr *MI) override;
43 
44   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
45                        const char *ExtraCode, raw_ostream &OS) override;
46   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
47                              const char *ExtraCode, raw_ostream &OS) override;
48 
49   void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
50   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
51                                    const MachineInstr *MI);
52 
53   // Wrapper needed for tblgenned pseudo lowering.
54   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
55     return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
56   }
57 };
58 }
59 
60 #define GEN_COMPRESS_INSTR
61 #include "RISCVGenCompressInstEmitter.inc"
62 void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
63   MCInst CInst;
64   bool Res = compressInst(CInst, Inst, *TM.getMCSubtargetInfo(),
65                           OutStreamer->getContext());
66   AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
67 }
68 
69 // Simple pseudo-instructions have their lowering (with expansion to real
70 // instructions) auto-generated.
71 #include "RISCVGenMCPseudoLowering.inc"
72 
73 void RISCVAsmPrinter::EmitInstruction(const MachineInstr *MI) {
74   // Do any auto-generated pseudo lowerings.
75   if (emitPseudoExpansionLowering(*OutStreamer, MI))
76     return;
77 
78   MCInst TmpInst;
79   LowerRISCVMachineInstrToMCInst(MI, TmpInst, *this);
80   EmitToStreamer(*OutStreamer, TmpInst);
81 }
82 
83 bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
84                                       const char *ExtraCode, raw_ostream &OS) {
85   // First try the generic code, which knows about modifiers like 'c' and 'n'.
86   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
87     return false;
88 
89   if (!ExtraCode) {
90     const MachineOperand &MO = MI->getOperand(OpNo);
91     switch (MO.getType()) {
92     case MachineOperand::MO_Immediate:
93       OS << MO.getImm();
94       return false;
95     case MachineOperand::MO_Register:
96       OS << RISCVInstPrinter::getRegisterName(MO.getReg());
97       return false;
98     default:
99       break;
100     }
101   }
102 
103   return true;
104 }
105 
106 bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
107                                             unsigned OpNo,
108                                             const char *ExtraCode,
109                                             raw_ostream &OS) {
110   if (!ExtraCode) {
111     const MachineOperand &MO = MI->getOperand(OpNo);
112     // For now, we only support register memory operands in registers and
113     // assume there is no addend
114     if (!MO.isReg())
115       return true;
116 
117     OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
118     return false;
119   }
120 
121   return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
122 }
123 
124 // Force static initialization.
125 extern "C" void LLVMInitializeRISCVAsmPrinter() {
126   RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
127   RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
128 }
129