1 | //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly 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 Sparc MCInst to a .s file. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "SparcInstPrinter.h" |
14 | #include "Sparc.h" |
15 | #include "llvm/MC/MCExpr.h" |
16 | #include "llvm/MC/MCInst.h" |
17 | #include "llvm/MC/MCRegisterInfo.h" |
18 | #include "llvm/MC/MCSubtargetInfo.h" |
19 | #include "llvm/MC/MCSymbol.h" |
20 | #include "llvm/Support/raw_ostream.h" |
21 | using namespace llvm; |
22 | |
23 | #define DEBUG_TYPE "asm-printer" |
24 | |
25 | // The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target |
26 | // namespace. But SPARC backend uses "SP" as its namespace. |
27 | namespace llvm { |
28 | namespace Sparc { |
29 | using namespace SP; |
30 | } |
31 | } |
32 | |
33 | #define GET_INSTRUCTION_NAME |
34 | #define PRINT_ALIAS_INSTR |
35 | #include "SparcGenAsmWriter.inc" |
36 | |
37 | bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const { |
38 | return (STI.hasFeature(Feature: Sparc::FeatureV9)) != 0; |
39 | } |
40 | |
41 | void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const { |
42 | OS << '%' << getRegisterName(Reg); |
43 | } |
44 | |
45 | void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg, |
46 | unsigned AltIdx) const { |
47 | OS << '%' << getRegisterName(Reg, AltIdx); |
48 | } |
49 | |
50 | void SparcInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
51 | StringRef Annot, const MCSubtargetInfo &STI, |
52 | raw_ostream &O) { |
53 | if (!printAliasInstr(MI, Address, STI, OS&: O) && |
54 | !printSparcAliasInstr(MI, STI, OS&: O)) |
55 | printInstruction(MI, Address, STI, O); |
56 | printAnnotation(OS&: O, Annot); |
57 | } |
58 | |
59 | bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, |
60 | const MCSubtargetInfo &STI, |
61 | raw_ostream &O) { |
62 | switch (MI->getOpcode()) { |
63 | default: return false; |
64 | case SP::JMPLrr: |
65 | case SP::JMPLri: { |
66 | if (MI->getNumOperands() != 3) |
67 | return false; |
68 | if (!MI->getOperand(i: 0).isReg()) |
69 | return false; |
70 | switch (MI->getOperand(i: 0).getReg()) { |
71 | default: return false; |
72 | case SP::G0: // jmp $addr | ret | retl |
73 | if (MI->getOperand(i: 2).isImm() && |
74 | MI->getOperand(i: 2).getImm() == 8) { |
75 | switch(MI->getOperand(i: 1).getReg()) { |
76 | default: break; |
77 | case SP::I7: O << "\tret" ; return true; |
78 | case SP::O7: O << "\tretl" ; return true; |
79 | } |
80 | } |
81 | O << "\tjmp " ; printMemOperand(MI, opNum: 1, STI, OS&: O); |
82 | return true; |
83 | case SP::O7: // call $addr |
84 | O << "\tcall " ; printMemOperand(MI, opNum: 1, STI, OS&: O); |
85 | return true; |
86 | } |
87 | } |
88 | case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ: |
89 | case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: { |
90 | if (isV9(STI) |
91 | || (MI->getNumOperands() != 3) |
92 | || (!MI->getOperand(i: 0).isReg()) |
93 | || (MI->getOperand(i: 0).getReg() != SP::FCC0)) |
94 | return false; |
95 | // if V8, skip printing %fcc0. |
96 | switch(MI->getOpcode()) { |
97 | default: |
98 | case SP::V9FCMPS: O << "\tfcmps " ; break; |
99 | case SP::V9FCMPD: O << "\tfcmpd " ; break; |
100 | case SP::V9FCMPQ: O << "\tfcmpq " ; break; |
101 | case SP::V9FCMPES: O << "\tfcmpes " ; break; |
102 | case SP::V9FCMPED: O << "\tfcmped " ; break; |
103 | case SP::V9FCMPEQ: O << "\tfcmpeq " ; break; |
104 | } |
105 | printOperand(MI, opNum: 1, STI, OS&: O); |
106 | O << ", " ; |
107 | printOperand(MI, opNum: 2, STI, OS&: O); |
108 | return true; |
109 | } |
110 | } |
111 | } |
112 | |
113 | void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, |
114 | const MCSubtargetInfo &STI, |
115 | raw_ostream &O) { |
116 | const MCOperand &MO = MI->getOperand (i: opNum); |
117 | |
118 | if (MO.isReg()) { |
119 | unsigned Reg = MO.getReg(); |
120 | if (isV9(STI)) |
121 | printRegName(OS&: O, Reg, AltIdx: SP::RegNamesStateReg); |
122 | else |
123 | printRegName(OS&: O, Reg); |
124 | return ; |
125 | } |
126 | |
127 | if (MO.isImm()) { |
128 | switch (MI->getOpcode()) { |
129 | default: |
130 | O << (int)MO.getImm(); |
131 | return; |
132 | |
133 | case SP::TICCri: // Fall through |
134 | case SP::TICCrr: // Fall through |
135 | case SP::TRAPri: // Fall through |
136 | case SP::TRAPrr: // Fall through |
137 | case SP::TXCCri: // Fall through |
138 | case SP::TXCCrr: // Fall through |
139 | // Only seven-bit values up to 127. |
140 | O << ((int) MO.getImm() & 0x7f); |
141 | return; |
142 | } |
143 | } |
144 | |
145 | assert(MO.isExpr() && "Unknown operand kind in printOperand" ); |
146 | MO.getExpr()->print(OS&: O, MAI: &MAI); |
147 | } |
148 | |
149 | void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, |
150 | const MCSubtargetInfo &STI, |
151 | raw_ostream &O) { |
152 | const MCOperand &Op1 = MI->getOperand(i: opNum); |
153 | const MCOperand &Op2 = MI->getOperand(i: opNum + 1); |
154 | |
155 | bool PrintedFirstOperand = false; |
156 | if (Op1.isReg() && Op1.getReg() != SP::G0) { |
157 | printOperand(MI, opNum, STI, O); |
158 | PrintedFirstOperand = true; |
159 | } |
160 | |
161 | // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've |
162 | // already printed the first one |
163 | const bool SkipSecondOperand = |
164 | PrintedFirstOperand && ((Op2.isReg() && Op2.getReg() == SP::G0) || |
165 | (Op2.isImm() && Op2.getImm() == 0)); |
166 | |
167 | if (!SkipSecondOperand) { |
168 | if (PrintedFirstOperand) |
169 | O << '+'; |
170 | printOperand(MI, opNum: opNum + 1, STI, O); |
171 | } |
172 | } |
173 | |
174 | void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, |
175 | const MCSubtargetInfo &STI, |
176 | raw_ostream &O) { |
177 | int CC = (int)MI->getOperand(i: opNum).getImm(); |
178 | switch (MI->getOpcode()) { |
179 | default: break; |
180 | case SP::FBCOND: |
181 | case SP::FBCONDA: |
182 | case SP::FBCOND_V9: |
183 | case SP::FBCONDA_V9: |
184 | case SP::BPFCC: |
185 | case SP::BPFCCA: |
186 | case SP::BPFCCNT: |
187 | case SP::BPFCCANT: |
188 | case SP::MOVFCCrr: case SP::V9MOVFCCrr: |
189 | case SP::MOVFCCri: case SP::V9MOVFCCri: |
190 | case SP::FMOVS_FCC: case SP::V9FMOVS_FCC: |
191 | case SP::FMOVD_FCC: case SP::V9FMOVD_FCC: |
192 | case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC: |
193 | // Make sure CC is a fp conditional flag. |
194 | CC = (CC < SPCC::FCC_BEGIN) ? (CC + SPCC::FCC_BEGIN) : CC; |
195 | break; |
196 | case SP::CBCOND: |
197 | case SP::CBCONDA: |
198 | // Make sure CC is a cp conditional flag. |
199 | CC = (CC < SPCC::CPCC_BEGIN) ? (CC + SPCC::CPCC_BEGIN) : CC; |
200 | break; |
201 | case SP::BPR: |
202 | case SP::BPRA: |
203 | case SP::BPRNT: |
204 | case SP::BPRANT: |
205 | case SP::MOVRri: |
206 | case SP::MOVRrr: |
207 | case SP::FMOVRS: |
208 | case SP::FMOVRD: |
209 | case SP::FMOVRQ: |
210 | // Make sure CC is a register conditional flag. |
211 | CC = (CC < SPCC::REG_BEGIN) ? (CC + SPCC::REG_BEGIN) : CC; |
212 | break; |
213 | } |
214 | O << SPARCCondCodeToString(CC: (SPCC::CondCodes)CC); |
215 | } |
216 | |
217 | bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, |
218 | const MCSubtargetInfo &STI, |
219 | raw_ostream &O) { |
220 | llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX." ); |
221 | return true; |
222 | } |
223 | |
224 | void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum, |
225 | const MCSubtargetInfo &STI, |
226 | raw_ostream &O) { |
227 | static const char *const TagNames[] = { |
228 | "#LoadLoad" , "#StoreLoad" , "#LoadStore" , "#StoreStore" , |
229 | "#Lookaside" , "#MemIssue" , "#Sync" }; |
230 | |
231 | unsigned Imm = MI->getOperand(i: opNum).getImm(); |
232 | |
233 | if (Imm > 127) { |
234 | O << Imm; |
235 | return; |
236 | } |
237 | |
238 | bool First = true; |
239 | for (unsigned i = 0; i < std::size(TagNames); i++) { |
240 | if (Imm & (1 << i)) { |
241 | O << (First ? "" : " | " ) << TagNames[i]; |
242 | First = false; |
243 | } |
244 | } |
245 | } |
246 | |
247 | void SparcInstPrinter::printASITag(const MCInst *MI, int opNum, |
248 | const MCSubtargetInfo &STI, raw_ostream &O) { |
249 | unsigned Imm = MI->getOperand(i: opNum).getImm(); |
250 | auto ASITag = SparcASITag::lookupASITagByEncoding(Encoding: Imm); |
251 | if (isV9(STI) && ASITag) |
252 | O << '#' << ASITag->Name; |
253 | else |
254 | O << Imm; |
255 | } |
256 | |
257 | void SparcInstPrinter::printPrefetchTag(const MCInst *MI, int opNum, |
258 | const MCSubtargetInfo &STI, |
259 | raw_ostream &O) { |
260 | unsigned Imm = MI->getOperand(i: opNum).getImm(); |
261 | auto PrefetchTag = SparcPrefetchTag::lookupPrefetchTagByEncoding(Encoding: Imm); |
262 | if (PrefetchTag) |
263 | O << '#' << PrefetchTag->Name; |
264 | else |
265 | O << Imm; |
266 | } |
267 | |