1 | //===-- CSKYInstPrinter.cpp - Convert CSKY MCInst to asm syntax ---------===// |
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 class prints an CSKY MCInst to a .s file. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "CSKYInstPrinter.h" |
13 | #include "MCTargetDesc/CSKYBaseInfo.h" |
14 | #include "MCTargetDesc/CSKYMCExpr.h" |
15 | #include "llvm/ADT/STLExtras.h" |
16 | #include "llvm/ADT/StringExtras.h" |
17 | #include "llvm/MC/MCAsmInfo.h" |
18 | #include "llvm/MC/MCExpr.h" |
19 | #include "llvm/MC/MCInst.h" |
20 | #include "llvm/MC/MCInstrInfo.h" |
21 | #include "llvm/MC/MCRegisterInfo.h" |
22 | #include "llvm/MC/MCSection.h" |
23 | #include "llvm/MC/MCSubtargetInfo.h" |
24 | #include "llvm/MC/MCSymbol.h" |
25 | #include "llvm/Support/CommandLine.h" |
26 | #include "llvm/Support/Debug.h" |
27 | #include "llvm/Support/ErrorHandling.h" |
28 | #include "llvm/Support/FormattedStream.h" |
29 | |
30 | using namespace llvm; |
31 | |
32 | #define DEBUG_TYPE "csky-asm-printer" |
33 | |
34 | // Include the auto-generated portion of the assembly writer. |
35 | #define PRINT_ALIAS_INSTR |
36 | #include "CSKYGenAsmWriter.inc" |
37 | |
38 | static cl::opt<bool> |
39 | NoAliases("csky-no-aliases" , |
40 | cl::desc("Disable the emission of assembler pseudo instructions" ), |
41 | cl::init(false), cl::Hidden); |
42 | |
43 | static cl::opt<bool> |
44 | ArchRegNames("csky-arch-reg-names" , |
45 | cl::desc("Print architectural register names rather than the " |
46 | "ABI names (such as r14 instead of sp)" ), |
47 | cl::init(Val: false), cl::Hidden); |
48 | |
49 | // The command-line flags above are used by llvm-mc and llc. They can be used by |
50 | // `llvm-objdump`, but we override their values here to handle options passed to |
51 | // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to |
52 | // be an easier way to allow these options in all these tools, without doing it |
53 | // this way. |
54 | bool CSKYInstPrinter::applyTargetSpecificCLOption(StringRef Opt) { |
55 | if (Opt == "no-aliases" ) { |
56 | NoAliases = true; |
57 | return true; |
58 | } |
59 | if (Opt == "numeric" ) { |
60 | ArchRegNames = true; |
61 | return true; |
62 | } |
63 | if (Opt == "debug" ) { |
64 | DebugFlag = true; |
65 | return true; |
66 | } |
67 | if (Opt == "abi-names" ) { |
68 | ABIRegNames = true; |
69 | return true; |
70 | } |
71 | |
72 | return false; |
73 | } |
74 | |
75 | void CSKYInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
76 | StringRef Annot, const MCSubtargetInfo &STI, |
77 | raw_ostream &O) { |
78 | const MCInst *NewMI = MI; |
79 | |
80 | if (NoAliases || !printAliasInstr(MI: NewMI, Address, STI, O)) |
81 | printInstruction(MI: NewMI, Address, STI, O); |
82 | printAnnotation(OS&: O, Annot); |
83 | } |
84 | |
85 | void CSKYInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const { |
86 | if (PrintBranchImmAsAddress) |
87 | O << getRegisterName(Reg, ABIRegNames ? CSKY::ABIRegAltName |
88 | : CSKY::NoRegAltName); |
89 | else |
90 | O << getRegisterName(Reg); |
91 | } |
92 | |
93 | void CSKYInstPrinter::printFPRRegName(raw_ostream &O, unsigned RegNo) const { |
94 | if (PrintBranchImmAsAddress) |
95 | O << getRegisterName(RegNo, CSKY::NoRegAltName); |
96 | else |
97 | O << getRegisterName(Reg: RegNo); |
98 | } |
99 | |
100 | void CSKYInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, |
101 | const MCSubtargetInfo &STI, raw_ostream &O, |
102 | const char *Modifier) { |
103 | assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported" ); |
104 | const MCOperand &MO = MI->getOperand(i: OpNo); |
105 | |
106 | if (MO.isReg()) { |
107 | unsigned Reg = MO.getReg(); |
108 | bool useABIName = false; |
109 | if (PrintBranchImmAsAddress) |
110 | useABIName = ABIRegNames; |
111 | else |
112 | useABIName = !ArchRegNames; |
113 | |
114 | if (Reg == CSKY::C) |
115 | O << "" ; |
116 | else if (STI.hasFeature(CSKY::FeatureJAVA)) { |
117 | if (Reg == CSKY::R23) |
118 | O << (useABIName ? "fp" : "r23" ); |
119 | else if (Reg == CSKY::R24) |
120 | O << (useABIName ? "top" : "r24" ); |
121 | else if (Reg == CSKY::R25) |
122 | O << (useABIName ? "bsp" : "r25" ); |
123 | else |
124 | printRegName(O, Reg); |
125 | } else |
126 | printRegName(O, Reg); |
127 | |
128 | return; |
129 | } |
130 | |
131 | if (MO.isImm()) { |
132 | uint64_t TSFlags = MII.get(Opcode: MI->getOpcode()).TSFlags; |
133 | |
134 | if (((TSFlags & CSKYII::AddrModeMask) != CSKYII::AddrModeNone) && |
135 | PrintBranchImmAsAddress) |
136 | O << formatHex(Value: MO.getImm()); |
137 | else |
138 | O << MO.getImm(); |
139 | return; |
140 | } |
141 | |
142 | assert(MO.isExpr() && "Unknown operand kind in printOperand" ); |
143 | MO.getExpr()->print(OS&: O, MAI: &MAI); |
144 | } |
145 | |
146 | void CSKYInstPrinter::printDataSymbol(const MCInst *MI, unsigned OpNo, |
147 | const MCSubtargetInfo &STI, |
148 | raw_ostream &O) { |
149 | const MCOperand &MO = MI->getOperand(i: OpNo); |
150 | |
151 | O << "[" ; |
152 | if (MO.isImm()) |
153 | O << MO.getImm(); |
154 | else |
155 | MO.getExpr()->print(OS&: O, MAI: &MAI); |
156 | O << "]" ; |
157 | } |
158 | |
159 | void CSKYInstPrinter::printConstpool(const MCInst *MI, uint64_t Address, |
160 | unsigned OpNo, const MCSubtargetInfo &STI, |
161 | raw_ostream &O) { |
162 | const MCOperand &MO = MI->getOperand(i: OpNo); |
163 | |
164 | if (MO.isImm()) { |
165 | if (PrintBranchImmAsAddress) { |
166 | uint64_t Target = Address + MO.getImm(); |
167 | Target &= 0xfffffffc; |
168 | O << formatHex(Value: Target); |
169 | } else { |
170 | O << MO.getImm(); |
171 | } |
172 | return; |
173 | } |
174 | |
175 | assert(MO.isExpr() && "Unknown operand kind in printConstpool" ); |
176 | |
177 | O << "[" ; |
178 | MO.getExpr()->print(OS&: O, MAI: &MAI); |
179 | O << "]" ; |
180 | } |
181 | |
182 | void CSKYInstPrinter::printCSKYSymbolOperand(const MCInst *MI, uint64_t Address, |
183 | unsigned OpNo, |
184 | const MCSubtargetInfo &STI, |
185 | raw_ostream &O) { |
186 | const MCOperand &MO = MI->getOperand(i: OpNo); |
187 | if (!MO.isImm()) { |
188 | return printOperand(MI, OpNo, STI, O); |
189 | } |
190 | |
191 | if (PrintBranchImmAsAddress) { |
192 | uint64_t Target = Address + MO.getImm(); |
193 | Target &= 0xffffffff; |
194 | O << formatHex(Value: Target); |
195 | } else { |
196 | O << MO.getImm(); |
197 | } |
198 | } |
199 | |
200 | void CSKYInstPrinter::printPSRFlag(const MCInst *MI, unsigned OpNo, |
201 | const MCSubtargetInfo &STI, raw_ostream &O) { |
202 | auto V = MI->getOperand(i: OpNo).getImm(); |
203 | |
204 | ListSeparator LS; |
205 | |
206 | if ((V >> 3) & 0x1) |
207 | O << LS << "ee" ; |
208 | if ((V >> 2) & 0x1) |
209 | O << LS << "ie" ; |
210 | if ((V >> 1) & 0x1) |
211 | O << LS << "fe" ; |
212 | if ((V >> 0) & 0x1) |
213 | O << LS << "af" ; |
214 | } |
215 | |
216 | void CSKYInstPrinter::printRegisterSeq(const MCInst *MI, unsigned OpNum, |
217 | const MCSubtargetInfo &STI, |
218 | raw_ostream &O) { |
219 | printRegName(O, Reg: MI->getOperand(i: OpNum).getReg()); |
220 | O << "-" ; |
221 | printRegName(O, Reg: MI->getOperand(i: OpNum + 1).getReg()); |
222 | } |
223 | |
224 | void CSKYInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum, |
225 | const MCSubtargetInfo &STI, |
226 | raw_ostream &O) { |
227 | auto V = MI->getOperand(i: OpNum).getImm(); |
228 | ListSeparator LS; |
229 | |
230 | if (V & 0xf) { |
231 | O << LS; |
232 | printRegName(O, CSKY::R4); |
233 | auto Offset = (V & 0xf) - 1; |
234 | if (Offset) { |
235 | O << "-" ; |
236 | printRegName(O, CSKY::R4 + Offset); |
237 | } |
238 | } |
239 | |
240 | if ((V >> 4) & 0x1) { |
241 | O << LS; |
242 | printRegName(O, CSKY::R15); |
243 | } |
244 | |
245 | if ((V >> 5) & 0x7) { |
246 | O << LS; |
247 | printRegName(O, CSKY::R16); |
248 | |
249 | auto Offset = ((V >> 5) & 0x7) - 1; |
250 | |
251 | if (Offset) { |
252 | O << "-" ; |
253 | printRegName(O, CSKY::R16 + Offset); |
254 | } |
255 | } |
256 | |
257 | if ((V >> 8) & 0x1) { |
258 | O << LS; |
259 | printRegName(O, CSKY::R28); |
260 | } |
261 | } |
262 | |
263 | const char *CSKYInstPrinter::getRegisterName(MCRegister Reg) { |
264 | return getRegisterName(Reg, ArchRegNames ? CSKY::NoRegAltName |
265 | : CSKY::ABIRegAltName); |
266 | } |
267 | |
268 | void CSKYInstPrinter::printFPR(const MCInst *MI, unsigned OpNo, |
269 | const MCSubtargetInfo &STI, raw_ostream &O) { |
270 | const MCOperand &MO = MI->getOperand(i: OpNo); |
271 | assert(MO.isReg()); |
272 | |
273 | printFPRRegName(O, RegNo: MO.getReg()); |
274 | } |
275 | |