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