1 | //===- HexagonAsmPrinter.cpp - Print machine instrs to Hexagon assembly ---===// |
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 Hexagon assembly language. This printer is |
11 | // the output mechanism used by `llc'. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "HexagonAsmPrinter.h" |
16 | #include "HexagonInstrInfo.h" |
17 | #include "HexagonRegisterInfo.h" |
18 | #include "HexagonSubtarget.h" |
19 | #include "MCTargetDesc/HexagonInstPrinter.h" |
20 | #include "MCTargetDesc/HexagonMCExpr.h" |
21 | #include "MCTargetDesc/HexagonMCInstrInfo.h" |
22 | #include "MCTargetDesc/HexagonMCTargetDesc.h" |
23 | #include "MCTargetDesc/HexagonTargetStreamer.h" |
24 | #include "TargetInfo/HexagonTargetInfo.h" |
25 | #include "llvm/ADT/StringExtras.h" |
26 | #include "llvm/ADT/StringRef.h" |
27 | #include "llvm/ADT/Twine.h" |
28 | #include "llvm/BinaryFormat/ELF.h" |
29 | #include "llvm/CodeGen/AsmPrinter.h" |
30 | #include "llvm/CodeGen/MachineBasicBlock.h" |
31 | #include "llvm/CodeGen/MachineFunction.h" |
32 | #include "llvm/CodeGen/MachineInstr.h" |
33 | #include "llvm/CodeGen/MachineOperand.h" |
34 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
35 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
36 | #include "llvm/MC/MCContext.h" |
37 | #include "llvm/MC/MCDirectives.h" |
38 | #include "llvm/MC/MCExpr.h" |
39 | #include "llvm/MC/MCInst.h" |
40 | #include "llvm/MC/MCRegisterInfo.h" |
41 | #include "llvm/MC/MCSectionELF.h" |
42 | #include "llvm/MC/MCStreamer.h" |
43 | #include "llvm/MC/MCSymbol.h" |
44 | #include "llvm/MC/TargetRegistry.h" |
45 | #include "llvm/Support/Casting.h" |
46 | #include "llvm/Support/Compiler.h" |
47 | #include "llvm/Support/ErrorHandling.h" |
48 | #include "llvm/Support/raw_ostream.h" |
49 | #include "llvm/Target/TargetMachine.h" |
50 | #include <cassert> |
51 | #include <cstdint> |
52 | #include <string> |
53 | |
54 | using namespace llvm; |
55 | |
56 | namespace llvm { |
57 | |
58 | void HexagonLowerToMC(const MCInstrInfo &MCII, const MachineInstr *MI, |
59 | MCInst &MCB, HexagonAsmPrinter &AP); |
60 | |
61 | } // end namespace llvm |
62 | |
63 | #define DEBUG_TYPE "asm-printer" |
64 | |
65 | // Given a scalar register return its pair. |
66 | inline static unsigned getHexagonRegisterPair(unsigned Reg, |
67 | const MCRegisterInfo *RI) { |
68 | assert(Hexagon::IntRegsRegClass.contains(Reg)); |
69 | unsigned Pair = *RI->superregs(Reg).begin(); |
70 | assert(Hexagon::DoubleRegsRegClass.contains(Pair)); |
71 | return Pair; |
72 | } |
73 | |
74 | void HexagonAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, |
75 | raw_ostream &O) { |
76 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
77 | |
78 | switch (MO.getType()) { |
79 | default: |
80 | llvm_unreachable ("<unknown operand type>" ); |
81 | case MachineOperand::MO_Register: |
82 | O << HexagonInstPrinter::getRegisterName(Reg: MO.getReg()); |
83 | return; |
84 | case MachineOperand::MO_Immediate: |
85 | O << MO.getImm(); |
86 | return; |
87 | case MachineOperand::MO_MachineBasicBlock: |
88 | MO.getMBB()->getSymbol()->print(OS&: O, MAI); |
89 | return; |
90 | case MachineOperand::MO_ConstantPoolIndex: |
91 | GetCPISymbol(CPID: MO.getIndex())->print(OS&: O, MAI); |
92 | return; |
93 | case MachineOperand::MO_GlobalAddress: |
94 | PrintSymbolOperand(MO, OS&: O); |
95 | return; |
96 | } |
97 | } |
98 | |
99 | // isBlockOnlyReachableByFallthrough - We need to override this since the |
100 | // default AsmPrinter does not print labels for any basic block that |
101 | // is only reachable by a fall through. That works for all cases except |
102 | // for the case in which the basic block is reachable by a fall through but |
103 | // through an indirect from a jump table. In this case, the jump table |
104 | // will contain a label not defined by AsmPrinter. |
105 | bool HexagonAsmPrinter::isBlockOnlyReachableByFallthrough( |
106 | const MachineBasicBlock *MBB) const { |
107 | if (MBB->hasAddressTaken()) |
108 | return false; |
109 | return AsmPrinter::isBlockOnlyReachableByFallthrough(MBB); |
110 | } |
111 | |
112 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
113 | bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
114 | const char *, |
115 | raw_ostream &OS) { |
116 | // Does this asm operand have a single letter operand modifier? |
117 | if (ExtraCode && ExtraCode[0]) { |
118 | if (ExtraCode[1] != 0) |
119 | return true; // Unknown modifier. |
120 | |
121 | switch (ExtraCode[0]) { |
122 | default: |
123 | // See if this is a generic print operand |
124 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS); |
125 | case 'L': |
126 | case 'H': { // The highest-numbered register of a pair. |
127 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
128 | const MachineFunction &MF = *MI->getParent()->getParent(); |
129 | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); |
130 | if (!MO.isReg()) |
131 | return true; |
132 | Register RegNumber = MO.getReg(); |
133 | // This should be an assert in the frontend. |
134 | if (Hexagon::DoubleRegsRegClass.contains(Reg: RegNumber)) |
135 | RegNumber = TRI->getSubReg(Reg: RegNumber, Idx: ExtraCode[0] == 'L' ? |
136 | Hexagon::isub_lo : |
137 | Hexagon::isub_hi); |
138 | OS << HexagonInstPrinter::getRegisterName(Reg: RegNumber); |
139 | return false; |
140 | } |
141 | case 'I': |
142 | // Write 'i' if an integer constant, otherwise nothing. Used to print |
143 | // addi vs add, etc. |
144 | if (MI->getOperand(i: OpNo).isImm()) |
145 | OS << "i" ; |
146 | return false; |
147 | } |
148 | } |
149 | |
150 | printOperand(MI, OpNo, O&: OS); |
151 | return false; |
152 | } |
153 | |
154 | bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
155 | unsigned OpNo, |
156 | const char *, |
157 | raw_ostream &O) { |
158 | if (ExtraCode && ExtraCode[0]) |
159 | return true; // Unknown modifier. |
160 | |
161 | const MachineOperand &Base = MI->getOperand(i: OpNo); |
162 | const MachineOperand &Offset = MI->getOperand(i: OpNo+1); |
163 | |
164 | if (Base.isReg()) |
165 | printOperand(MI, OpNo, O); |
166 | else |
167 | llvm_unreachable("Unimplemented" ); |
168 | |
169 | if (Offset.isImm()) { |
170 | if (Offset.getImm()) |
171 | O << "+#" << Offset.getImm(); |
172 | } else { |
173 | llvm_unreachable("Unimplemented" ); |
174 | } |
175 | |
176 | return false; |
177 | } |
178 | |
179 | static MCSymbol *smallData(AsmPrinter &AP, const MachineInstr &MI, |
180 | MCStreamer &OutStreamer, const MCOperand &Imm, |
181 | int AlignSize, const MCSubtargetInfo& STI) { |
182 | MCSymbol *Sym; |
183 | int64_t Value; |
184 | if (Imm.getExpr()->evaluateAsAbsolute(Res&: Value)) { |
185 | StringRef sectionPrefix; |
186 | std::string ImmString; |
187 | StringRef Name; |
188 | if (AlignSize == 8) { |
189 | Name = ".CONST_0000000000000000" ; |
190 | sectionPrefix = ".gnu.linkonce.l8" ; |
191 | ImmString = utohexstr(X: Value); |
192 | } else { |
193 | Name = ".CONST_00000000" ; |
194 | sectionPrefix = ".gnu.linkonce.l4" ; |
195 | ImmString = utohexstr(X: static_cast<uint32_t>(Value)); |
196 | } |
197 | |
198 | std::string symbolName = // Yes, leading zeros are kept. |
199 | Name.drop_back(N: ImmString.size()).str() + ImmString; |
200 | std::string sectionName = sectionPrefix.str() + symbolName; |
201 | |
202 | MCSectionELF *Section = OutStreamer.getContext().getELFSection( |
203 | Section: sectionName, Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
204 | OutStreamer.switchSection(Section); |
205 | |
206 | Sym = AP.OutContext.getOrCreateSymbol(Name: Twine(symbolName)); |
207 | if (Sym->isUndefined()) { |
208 | OutStreamer.emitLabel(Symbol: Sym); |
209 | OutStreamer.emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Global); |
210 | OutStreamer.emitIntValue(Value, Size: AlignSize); |
211 | OutStreamer.emitCodeAlignment(Alignment: Align(AlignSize), STI: &STI); |
212 | } |
213 | } else { |
214 | assert(Imm.isExpr() && "Expected expression and found none" ); |
215 | const MachineOperand &MO = MI.getOperand(i: 1); |
216 | assert(MO.isGlobal() || MO.isCPI() || MO.isJTI()); |
217 | MCSymbol *MOSymbol = nullptr; |
218 | if (MO.isGlobal()) |
219 | MOSymbol = AP.getSymbol(GV: MO.getGlobal()); |
220 | else if (MO.isCPI()) |
221 | MOSymbol = AP.GetCPISymbol(CPID: MO.getIndex()); |
222 | else if (MO.isJTI()) |
223 | MOSymbol = AP.GetJTISymbol(JTID: MO.getIndex()); |
224 | else |
225 | llvm_unreachable("Unknown operand type!" ); |
226 | |
227 | StringRef SymbolName = MOSymbol->getName(); |
228 | std::string LitaName = ".CONST_" + SymbolName.str(); |
229 | |
230 | MCSectionELF *Section = OutStreamer.getContext().getELFSection( |
231 | Section: ".lita" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
232 | |
233 | OutStreamer.switchSection(Section); |
234 | Sym = AP.OutContext.getOrCreateSymbol(Name: Twine(LitaName)); |
235 | if (Sym->isUndefined()) { |
236 | OutStreamer.emitLabel(Symbol: Sym); |
237 | OutStreamer.emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Local); |
238 | OutStreamer.emitValue(Value: Imm.getExpr(), Size: AlignSize); |
239 | OutStreamer.emitCodeAlignment(Alignment: Align(AlignSize), STI: &STI); |
240 | } |
241 | } |
242 | return Sym; |
243 | } |
244 | |
245 | static MCInst ScaleVectorOffset(MCInst &Inst, unsigned OpNo, |
246 | unsigned VectorSize, MCContext &Ctx) { |
247 | MCInst T; |
248 | T.setOpcode(Inst.getOpcode()); |
249 | for (unsigned i = 0, n = Inst.getNumOperands(); i != n; ++i) { |
250 | if (i != OpNo) { |
251 | T.addOperand(Op: Inst.getOperand(i)); |
252 | continue; |
253 | } |
254 | MCOperand &ImmOp = Inst.getOperand(i); |
255 | const auto *HE = static_cast<const HexagonMCExpr*>(ImmOp.getExpr()); |
256 | int32_t V = cast<MCConstantExpr>(Val: HE->getExpr())->getValue(); |
257 | auto *NewCE = MCConstantExpr::create(Value: V / int32_t(VectorSize), Ctx); |
258 | auto *NewHE = HexagonMCExpr::create(Expr: NewCE, Ctx); |
259 | T.addOperand(Op: MCOperand::createExpr(Val: NewHE)); |
260 | } |
261 | return T; |
262 | } |
263 | |
264 | void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst, |
265 | const MachineInstr &MI) { |
266 | MCInst &MappedInst = static_cast <MCInst &>(Inst); |
267 | const MCRegisterInfo *RI = OutStreamer->getContext().getRegisterInfo(); |
268 | const MachineFunction &MF = *MI.getParent()->getParent(); |
269 | auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); |
270 | unsigned VectorSize = HRI.getRegSizeInBits(RC: Hexagon::HvxVRRegClass) / 8; |
271 | |
272 | switch (Inst.getOpcode()) { |
273 | default: |
274 | return; |
275 | |
276 | case Hexagon::A2_iconst: { |
277 | Inst.setOpcode(Hexagon::A2_addi); |
278 | MCOperand Reg = Inst.getOperand(i: 0); |
279 | MCOperand S16 = Inst.getOperand(i: 1); |
280 | HexagonMCInstrInfo::setMustNotExtend(Expr: *S16.getExpr()); |
281 | HexagonMCInstrInfo::setS27_2_reloc(Expr: *S16.getExpr()); |
282 | Inst.clear(); |
283 | Inst.addOperand(Op: Reg); |
284 | Inst.addOperand(Op: MCOperand::createReg(Reg: Hexagon::R0)); |
285 | Inst.addOperand(Op: S16); |
286 | break; |
287 | } |
288 | |
289 | case Hexagon::A2_tfrf: { |
290 | const MCConstantExpr *Zero = MCConstantExpr::create(Value: 0, Ctx&: OutContext); |
291 | Inst.setOpcode(Hexagon::A2_paddif); |
292 | Inst.addOperand(Op: MCOperand::createExpr(Val: Zero)); |
293 | break; |
294 | } |
295 | |
296 | case Hexagon::A2_tfrt: { |
297 | const MCConstantExpr *Zero = MCConstantExpr::create(Value: 0, Ctx&: OutContext); |
298 | Inst.setOpcode(Hexagon::A2_paddit); |
299 | Inst.addOperand(Op: MCOperand::createExpr(Val: Zero)); |
300 | break; |
301 | } |
302 | |
303 | case Hexagon::A2_tfrfnew: { |
304 | const MCConstantExpr *Zero = MCConstantExpr::create(Value: 0, Ctx&: OutContext); |
305 | Inst.setOpcode(Hexagon::A2_paddifnew); |
306 | Inst.addOperand(Op: MCOperand::createExpr(Val: Zero)); |
307 | break; |
308 | } |
309 | |
310 | case Hexagon::A2_tfrtnew: { |
311 | const MCConstantExpr *Zero = MCConstantExpr::create(Value: 0, Ctx&: OutContext); |
312 | Inst.setOpcode(Hexagon::A2_padditnew); |
313 | Inst.addOperand(Op: MCOperand::createExpr(Val: Zero)); |
314 | break; |
315 | } |
316 | |
317 | case Hexagon::A2_zxtb: { |
318 | const MCConstantExpr *C255 = MCConstantExpr::create(Value: 255, Ctx&: OutContext); |
319 | Inst.setOpcode(Hexagon::A2_andir); |
320 | Inst.addOperand(Op: MCOperand::createExpr(Val: C255)); |
321 | break; |
322 | } |
323 | |
324 | // "$dst = CONST64(#$src1)", |
325 | case Hexagon::CONST64: |
326 | if (!OutStreamer->hasRawTextSupport()) { |
327 | const MCOperand &Imm = MappedInst.getOperand(i: 1); |
328 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
329 | |
330 | MCSymbol *Sym = |
331 | smallData(AP&: *this, MI, OutStreamer&: *OutStreamer, Imm, AlignSize: 8, STI: getSubtargetInfo()); |
332 | |
333 | OutStreamer->switchSection(Section: Current.first, Subsec: Current.second); |
334 | MCInst TmpInst; |
335 | MCOperand &Reg = MappedInst.getOperand(i: 0); |
336 | TmpInst.setOpcode(Hexagon::L2_loadrdgp); |
337 | TmpInst.addOperand(Op: Reg); |
338 | TmpInst.addOperand(Op: MCOperand::createExpr( |
339 | Val: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext))); |
340 | MappedInst = TmpInst; |
341 | |
342 | } |
343 | break; |
344 | case Hexagon::CONST32: |
345 | if (!OutStreamer->hasRawTextSupport()) { |
346 | MCOperand &Imm = MappedInst.getOperand(i: 1); |
347 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
348 | MCSymbol *Sym = |
349 | smallData(AP&: *this, MI, OutStreamer&: *OutStreamer, Imm, AlignSize: 4, STI: getSubtargetInfo()); |
350 | OutStreamer->switchSection(Section: Current.first, Subsec: Current.second); |
351 | MCInst TmpInst; |
352 | MCOperand &Reg = MappedInst.getOperand(i: 0); |
353 | TmpInst.setOpcode(Hexagon::L2_loadrigp); |
354 | TmpInst.addOperand(Op: Reg); |
355 | TmpInst.addOperand(Op: MCOperand::createExpr(Val: HexagonMCExpr::create( |
356 | Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext), Ctx&: OutContext))); |
357 | MappedInst = TmpInst; |
358 | } |
359 | break; |
360 | |
361 | // C2_pxfer_map maps to C2_or instruction. Though, it's possible to use |
362 | // C2_or during instruction selection itself but it results |
363 | // into suboptimal code. |
364 | case Hexagon::C2_pxfer_map: { |
365 | MCOperand &Ps = Inst.getOperand(i: 1); |
366 | MappedInst.setOpcode(Hexagon::C2_or); |
367 | MappedInst.addOperand(Op: Ps); |
368 | return; |
369 | } |
370 | |
371 | // Vector reduce complex multiply by scalar, Rt & 1 map to :hi else :lo |
372 | // The insn is mapped from the 4 operand to the 3 operand raw form taking |
373 | // 3 register pairs. |
374 | case Hexagon::M2_vrcmpys_acc_s1: { |
375 | MCOperand &Rt = Inst.getOperand(i: 3); |
376 | assert(Rt.isReg() && "Expected register and none was found" ); |
377 | unsigned Reg = RI->getEncodingValue(Reg: Rt.getReg()); |
378 | if (Reg & 1) |
379 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_h); |
380 | else |
381 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_l); |
382 | Rt.setReg(getHexagonRegisterPair(Reg: Rt.getReg(), RI)); |
383 | return; |
384 | } |
385 | case Hexagon::M2_vrcmpys_s1: { |
386 | MCOperand &Rt = Inst.getOperand(i: 2); |
387 | assert(Rt.isReg() && "Expected register and none was found" ); |
388 | unsigned Reg = RI->getEncodingValue(Reg: Rt.getReg()); |
389 | if (Reg & 1) |
390 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1_h); |
391 | else |
392 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1_l); |
393 | Rt.setReg(getHexagonRegisterPair(Reg: Rt.getReg(), RI)); |
394 | return; |
395 | } |
396 | |
397 | case Hexagon::M2_vrcmpys_s1rp: { |
398 | MCOperand &Rt = Inst.getOperand(i: 2); |
399 | assert(Rt.isReg() && "Expected register and none was found" ); |
400 | unsigned Reg = RI->getEncodingValue(Reg: Rt.getReg()); |
401 | if (Reg & 1) |
402 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1rp_h); |
403 | else |
404 | MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1rp_l); |
405 | Rt.setReg(getHexagonRegisterPair(Reg: Rt.getReg(), RI)); |
406 | return; |
407 | } |
408 | |
409 | case Hexagon::A4_boundscheck: { |
410 | MCOperand &Rs = Inst.getOperand(i: 1); |
411 | assert(Rs.isReg() && "Expected register and none was found" ); |
412 | unsigned Reg = RI->getEncodingValue(Reg: Rs.getReg()); |
413 | if (Reg & 1) // Odd mapped to raw:hi, regpair is rodd:odd-1, like r3:2 |
414 | MappedInst.setOpcode(Hexagon::A4_boundscheck_hi); |
415 | else // raw:lo |
416 | MappedInst.setOpcode(Hexagon::A4_boundscheck_lo); |
417 | Rs.setReg(getHexagonRegisterPair(Reg: Rs.getReg(), RI)); |
418 | return; |
419 | } |
420 | |
421 | case Hexagon::PS_call_nr: |
422 | Inst.setOpcode(Hexagon::J2_call); |
423 | break; |
424 | |
425 | case Hexagon::S5_asrhub_rnd_sat_goodsyntax: { |
426 | MCOperand &MO = MappedInst.getOperand(i: 2); |
427 | int64_t Imm; |
428 | MCExpr const *Expr = MO.getExpr(); |
429 | bool Success = Expr->evaluateAsAbsolute(Res&: Imm); |
430 | assert(Success && "Expected immediate and none was found" ); |
431 | (void)Success; |
432 | MCInst TmpInst; |
433 | if (Imm == 0) { |
434 | TmpInst.setOpcode(Hexagon::S2_vsathub); |
435 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
436 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 1)); |
437 | MappedInst = TmpInst; |
438 | return; |
439 | } |
440 | TmpInst.setOpcode(Hexagon::S5_asrhub_rnd_sat); |
441 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
442 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 1)); |
443 | const MCExpr *One = MCConstantExpr::create(Value: 1, Ctx&: OutContext); |
444 | const MCExpr *Sub = MCBinaryExpr::createSub(LHS: Expr, RHS: One, Ctx&: OutContext); |
445 | TmpInst.addOperand( |
446 | Op: MCOperand::createExpr(Val: HexagonMCExpr::create(Expr: Sub, Ctx&: OutContext))); |
447 | MappedInst = TmpInst; |
448 | return; |
449 | } |
450 | |
451 | case Hexagon::S5_vasrhrnd_goodsyntax: |
452 | case Hexagon::S2_asr_i_p_rnd_goodsyntax: { |
453 | MCOperand &MO2 = MappedInst.getOperand(i: 2); |
454 | MCExpr const *Expr = MO2.getExpr(); |
455 | int64_t Imm; |
456 | bool Success = Expr->evaluateAsAbsolute(Res&: Imm); |
457 | assert(Success && "Expected immediate and none was found" ); |
458 | (void)Success; |
459 | MCInst TmpInst; |
460 | if (Imm == 0) { |
461 | TmpInst.setOpcode(Hexagon::A2_combinew); |
462 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
463 | MCOperand &MO1 = MappedInst.getOperand(i: 1); |
464 | MCRegister High = RI->getSubReg(Reg: MO1.getReg(), Idx: Hexagon::isub_hi); |
465 | MCRegister Low = RI->getSubReg(Reg: MO1.getReg(), Idx: Hexagon::isub_lo); |
466 | // Add a new operand for the second register in the pair. |
467 | TmpInst.addOperand(Op: MCOperand::createReg(Reg: High)); |
468 | TmpInst.addOperand(Op: MCOperand::createReg(Reg: Low)); |
469 | MappedInst = TmpInst; |
470 | return; |
471 | } |
472 | |
473 | if (Inst.getOpcode() == Hexagon::S2_asr_i_p_rnd_goodsyntax) |
474 | TmpInst.setOpcode(Hexagon::S2_asr_i_p_rnd); |
475 | else |
476 | TmpInst.setOpcode(Hexagon::S5_vasrhrnd); |
477 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
478 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 1)); |
479 | const MCExpr *One = MCConstantExpr::create(Value: 1, Ctx&: OutContext); |
480 | const MCExpr *Sub = MCBinaryExpr::createSub(LHS: Expr, RHS: One, Ctx&: OutContext); |
481 | TmpInst.addOperand( |
482 | Op: MCOperand::createExpr(Val: HexagonMCExpr::create(Expr: Sub, Ctx&: OutContext))); |
483 | MappedInst = TmpInst; |
484 | return; |
485 | } |
486 | |
487 | // if ("#u5==0") Assembler mapped to: "Rd=Rs"; else Rd=asr(Rs,#u5-1):rnd |
488 | case Hexagon::S2_asr_i_r_rnd_goodsyntax: { |
489 | MCOperand &MO = Inst.getOperand(i: 2); |
490 | MCExpr const *Expr = MO.getExpr(); |
491 | int64_t Imm; |
492 | bool Success = Expr->evaluateAsAbsolute(Res&: Imm); |
493 | assert(Success && "Expected immediate and none was found" ); |
494 | (void)Success; |
495 | MCInst TmpInst; |
496 | if (Imm == 0) { |
497 | TmpInst.setOpcode(Hexagon::A2_tfr); |
498 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
499 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 1)); |
500 | MappedInst = TmpInst; |
501 | return; |
502 | } |
503 | TmpInst.setOpcode(Hexagon::S2_asr_i_r_rnd); |
504 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 0)); |
505 | TmpInst.addOperand(Op: MappedInst.getOperand(i: 1)); |
506 | const MCExpr *One = MCConstantExpr::create(Value: 1, Ctx&: OutContext); |
507 | const MCExpr *Sub = MCBinaryExpr::createSub(LHS: Expr, RHS: One, Ctx&: OutContext); |
508 | TmpInst.addOperand( |
509 | Op: MCOperand::createExpr(Val: HexagonMCExpr::create(Expr: Sub, Ctx&: OutContext))); |
510 | MappedInst = TmpInst; |
511 | return; |
512 | } |
513 | |
514 | // Translate a "$Rdd = #imm" to "$Rdd = combine(#[-1,0], #imm)" |
515 | case Hexagon::A2_tfrpi: { |
516 | MCInst TmpInst; |
517 | MCOperand &Rdd = MappedInst.getOperand(i: 0); |
518 | MCOperand &MO = MappedInst.getOperand(i: 1); |
519 | |
520 | TmpInst.setOpcode(Hexagon::A2_combineii); |
521 | TmpInst.addOperand(Op: Rdd); |
522 | int64_t Imm; |
523 | bool Success = MO.getExpr()->evaluateAsAbsolute(Res&: Imm); |
524 | if (Success && Imm < 0) { |
525 | const MCExpr *MOne = MCConstantExpr::create(Value: -1, Ctx&: OutContext); |
526 | const HexagonMCExpr *E = HexagonMCExpr::create(Expr: MOne, Ctx&: OutContext); |
527 | TmpInst.addOperand(Op: MCOperand::createExpr(Val: E)); |
528 | } else { |
529 | const MCExpr *Zero = MCConstantExpr::create(Value: 0, Ctx&: OutContext); |
530 | const HexagonMCExpr *E = HexagonMCExpr::create(Expr: Zero, Ctx&: OutContext); |
531 | TmpInst.addOperand(Op: MCOperand::createExpr(Val: E)); |
532 | } |
533 | TmpInst.addOperand(Op: MO); |
534 | MappedInst = TmpInst; |
535 | return; |
536 | } |
537 | |
538 | // Translate a "$Rdd = $Rss" to "$Rdd = combine($Rs, $Rt)" |
539 | case Hexagon::A2_tfrp: { |
540 | MCOperand &MO = MappedInst.getOperand(i: 1); |
541 | MCRegister High = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_hi); |
542 | MCRegister Low = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_lo); |
543 | MO.setReg(High); |
544 | // Add a new operand for the second register in the pair. |
545 | MappedInst.addOperand(Op: MCOperand::createReg(Reg: Low)); |
546 | MappedInst.setOpcode(Hexagon::A2_combinew); |
547 | return; |
548 | } |
549 | |
550 | case Hexagon::A2_tfrpt: |
551 | case Hexagon::A2_tfrpf: { |
552 | MCOperand &MO = MappedInst.getOperand(i: 2); |
553 | MCRegister High = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_hi); |
554 | MCRegister Low = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_lo); |
555 | MO.setReg(High); |
556 | // Add a new operand for the second register in the pair. |
557 | MappedInst.addOperand(Op: MCOperand::createReg(Reg: Low)); |
558 | MappedInst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrpt) |
559 | ? Hexagon::C2_ccombinewt |
560 | : Hexagon::C2_ccombinewf); |
561 | return; |
562 | } |
563 | |
564 | case Hexagon::A2_tfrptnew: |
565 | case Hexagon::A2_tfrpfnew: { |
566 | MCOperand &MO = MappedInst.getOperand(i: 2); |
567 | MCRegister High = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_hi); |
568 | MCRegister Low = RI->getSubReg(Reg: MO.getReg(), Idx: Hexagon::isub_lo); |
569 | MO.setReg(High); |
570 | // Add a new operand for the second register in the pair. |
571 | MappedInst.addOperand(Op: MCOperand::createReg(Reg: Low)); |
572 | MappedInst.setOpcode(Inst.getOpcode() == Hexagon::A2_tfrptnew |
573 | ? Hexagon::C2_ccombinewnewt |
574 | : Hexagon::C2_ccombinewnewf); |
575 | return; |
576 | } |
577 | |
578 | case Hexagon::M2_mpysmi: { |
579 | MCOperand &Imm = MappedInst.getOperand(i: 2); |
580 | MCExpr const *Expr = Imm.getExpr(); |
581 | int64_t Value; |
582 | bool Success = Expr->evaluateAsAbsolute(Res&: Value); |
583 | assert(Success); |
584 | (void)Success; |
585 | if (Value < 0 && Value > -256) { |
586 | MappedInst.setOpcode(Hexagon::M2_mpysin); |
587 | Imm.setExpr(HexagonMCExpr::create( |
588 | Expr: MCUnaryExpr::createMinus(Expr, Ctx&: OutContext), Ctx&: OutContext)); |
589 | } else |
590 | MappedInst.setOpcode(Hexagon::M2_mpysip); |
591 | return; |
592 | } |
593 | |
594 | case Hexagon::A2_addsp: { |
595 | MCOperand &Rt = Inst.getOperand(i: 1); |
596 | assert(Rt.isReg() && "Expected register and none was found" ); |
597 | unsigned Reg = RI->getEncodingValue(Reg: Rt.getReg()); |
598 | if (Reg & 1) |
599 | MappedInst.setOpcode(Hexagon::A2_addsph); |
600 | else |
601 | MappedInst.setOpcode(Hexagon::A2_addspl); |
602 | Rt.setReg(getHexagonRegisterPair(Reg: Rt.getReg(), RI)); |
603 | return; |
604 | } |
605 | |
606 | case Hexagon::V6_vd0: { |
607 | MCInst TmpInst; |
608 | assert(Inst.getOperand(0).isReg() && |
609 | "Expected register and none was found" ); |
610 | |
611 | TmpInst.setOpcode(Hexagon::V6_vxor); |
612 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
613 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
614 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
615 | MappedInst = TmpInst; |
616 | return; |
617 | } |
618 | |
619 | case Hexagon::V6_vdd0: { |
620 | MCInst TmpInst; |
621 | assert (Inst.getOperand(0).isReg() && |
622 | "Expected register and none was found" ); |
623 | |
624 | TmpInst.setOpcode(Hexagon::V6_vsubw_dv); |
625 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
626 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
627 | TmpInst.addOperand(Op: Inst.getOperand(i: 0)); |
628 | MappedInst = TmpInst; |
629 | return; |
630 | } |
631 | |
632 | case Hexagon::V6_vL32Ub_pi: |
633 | case Hexagon::V6_vL32b_cur_pi: |
634 | case Hexagon::V6_vL32b_nt_cur_pi: |
635 | case Hexagon::V6_vL32b_pi: |
636 | case Hexagon::V6_vL32b_nt_pi: |
637 | case Hexagon::V6_vL32b_nt_tmp_pi: |
638 | case Hexagon::V6_vL32b_tmp_pi: |
639 | MappedInst = ScaleVectorOffset(Inst, OpNo: 3, VectorSize, Ctx&: OutContext); |
640 | return; |
641 | |
642 | case Hexagon::V6_vL32Ub_ai: |
643 | case Hexagon::V6_vL32b_ai: |
644 | case Hexagon::V6_vL32b_cur_ai: |
645 | case Hexagon::V6_vL32b_nt_ai: |
646 | case Hexagon::V6_vL32b_nt_cur_ai: |
647 | case Hexagon::V6_vL32b_nt_tmp_ai: |
648 | case Hexagon::V6_vL32b_tmp_ai: |
649 | MappedInst = ScaleVectorOffset(Inst, OpNo: 2, VectorSize, Ctx&: OutContext); |
650 | return; |
651 | |
652 | case Hexagon::V6_vS32Ub_pi: |
653 | case Hexagon::V6_vS32b_new_pi: |
654 | case Hexagon::V6_vS32b_nt_new_pi: |
655 | case Hexagon::V6_vS32b_nt_pi: |
656 | case Hexagon::V6_vS32b_pi: |
657 | MappedInst = ScaleVectorOffset(Inst, OpNo: 2, VectorSize, Ctx&: OutContext); |
658 | return; |
659 | |
660 | case Hexagon::V6_vS32Ub_ai: |
661 | case Hexagon::V6_vS32b_ai: |
662 | case Hexagon::V6_vS32b_new_ai: |
663 | case Hexagon::V6_vS32b_nt_ai: |
664 | case Hexagon::V6_vS32b_nt_new_ai: |
665 | MappedInst = ScaleVectorOffset(Inst, OpNo: 1, VectorSize, Ctx&: OutContext); |
666 | return; |
667 | |
668 | case Hexagon::V6_vL32b_cur_npred_pi: |
669 | case Hexagon::V6_vL32b_cur_pred_pi: |
670 | case Hexagon::V6_vL32b_npred_pi: |
671 | case Hexagon::V6_vL32b_nt_cur_npred_pi: |
672 | case Hexagon::V6_vL32b_nt_cur_pred_pi: |
673 | case Hexagon::V6_vL32b_nt_npred_pi: |
674 | case Hexagon::V6_vL32b_nt_pred_pi: |
675 | case Hexagon::V6_vL32b_nt_tmp_npred_pi: |
676 | case Hexagon::V6_vL32b_nt_tmp_pred_pi: |
677 | case Hexagon::V6_vL32b_pred_pi: |
678 | case Hexagon::V6_vL32b_tmp_npred_pi: |
679 | case Hexagon::V6_vL32b_tmp_pred_pi: |
680 | MappedInst = ScaleVectorOffset(Inst, OpNo: 4, VectorSize, Ctx&: OutContext); |
681 | return; |
682 | |
683 | case Hexagon::V6_vL32b_cur_npred_ai: |
684 | case Hexagon::V6_vL32b_cur_pred_ai: |
685 | case Hexagon::V6_vL32b_npred_ai: |
686 | case Hexagon::V6_vL32b_nt_cur_npred_ai: |
687 | case Hexagon::V6_vL32b_nt_cur_pred_ai: |
688 | case Hexagon::V6_vL32b_nt_npred_ai: |
689 | case Hexagon::V6_vL32b_nt_pred_ai: |
690 | case Hexagon::V6_vL32b_nt_tmp_npred_ai: |
691 | case Hexagon::V6_vL32b_nt_tmp_pred_ai: |
692 | case Hexagon::V6_vL32b_pred_ai: |
693 | case Hexagon::V6_vL32b_tmp_npred_ai: |
694 | case Hexagon::V6_vL32b_tmp_pred_ai: |
695 | MappedInst = ScaleVectorOffset(Inst, OpNo: 3, VectorSize, Ctx&: OutContext); |
696 | return; |
697 | |
698 | case Hexagon::V6_vS32Ub_npred_pi: |
699 | case Hexagon::V6_vS32Ub_pred_pi: |
700 | case Hexagon::V6_vS32b_new_npred_pi: |
701 | case Hexagon::V6_vS32b_new_pred_pi: |
702 | case Hexagon::V6_vS32b_npred_pi: |
703 | case Hexagon::V6_vS32b_nqpred_pi: |
704 | case Hexagon::V6_vS32b_nt_new_npred_pi: |
705 | case Hexagon::V6_vS32b_nt_new_pred_pi: |
706 | case Hexagon::V6_vS32b_nt_npred_pi: |
707 | case Hexagon::V6_vS32b_nt_nqpred_pi: |
708 | case Hexagon::V6_vS32b_nt_pred_pi: |
709 | case Hexagon::V6_vS32b_nt_qpred_pi: |
710 | case Hexagon::V6_vS32b_pred_pi: |
711 | case Hexagon::V6_vS32b_qpred_pi: |
712 | MappedInst = ScaleVectorOffset(Inst, OpNo: 3, VectorSize, Ctx&: OutContext); |
713 | return; |
714 | |
715 | case Hexagon::V6_vS32Ub_npred_ai: |
716 | case Hexagon::V6_vS32Ub_pred_ai: |
717 | case Hexagon::V6_vS32b_new_npred_ai: |
718 | case Hexagon::V6_vS32b_new_pred_ai: |
719 | case Hexagon::V6_vS32b_npred_ai: |
720 | case Hexagon::V6_vS32b_nqpred_ai: |
721 | case Hexagon::V6_vS32b_nt_new_npred_ai: |
722 | case Hexagon::V6_vS32b_nt_new_pred_ai: |
723 | case Hexagon::V6_vS32b_nt_npred_ai: |
724 | case Hexagon::V6_vS32b_nt_nqpred_ai: |
725 | case Hexagon::V6_vS32b_nt_pred_ai: |
726 | case Hexagon::V6_vS32b_nt_qpred_ai: |
727 | case Hexagon::V6_vS32b_pred_ai: |
728 | case Hexagon::V6_vS32b_qpred_ai: |
729 | MappedInst = ScaleVectorOffset(Inst, OpNo: 2, VectorSize, Ctx&: OutContext); |
730 | return; |
731 | |
732 | // V65+ |
733 | case Hexagon::V6_vS32b_srls_ai: |
734 | MappedInst = ScaleVectorOffset(Inst, OpNo: 1, VectorSize, Ctx&: OutContext); |
735 | return; |
736 | |
737 | case Hexagon::V6_vS32b_srls_pi: |
738 | MappedInst = ScaleVectorOffset(Inst, OpNo: 2, VectorSize, Ctx&: OutContext); |
739 | return; |
740 | } |
741 | } |
742 | |
743 | /// Print out a single Hexagon MI to the current output stream. |
744 | void HexagonAsmPrinter::emitInstruction(const MachineInstr *MI) { |
745 | Hexagon_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
746 | Features: getSubtargetInfo().getFeatureBits()); |
747 | |
748 | MCInst MCB; |
749 | MCB.setOpcode(Hexagon::BUNDLE); |
750 | MCB.addOperand(Op: MCOperand::createImm(Val: 0)); |
751 | const MCInstrInfo &MCII = *Subtarget->getInstrInfo(); |
752 | |
753 | if (MI->isBundle()) { |
754 | const MachineBasicBlock* MBB = MI->getParent(); |
755 | MachineBasicBlock::const_instr_iterator MII = MI->getIterator(); |
756 | |
757 | for (++MII; MII != MBB->instr_end() && MII->isInsideBundle(); ++MII) |
758 | if (!MII->isDebugInstr() && !MII->isImplicitDef()) |
759 | HexagonLowerToMC(MCII, MI: &*MII, MCB, AP&: *this); |
760 | } else { |
761 | HexagonLowerToMC(MCII, MI, MCB, AP&: *this); |
762 | } |
763 | |
764 | const MachineFunction &MF = *MI->getParent()->getParent(); |
765 | const auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); |
766 | if (MI->isBundle() && HII.getBundleNoShuf(MIB: *MI)) |
767 | HexagonMCInstrInfo::setMemReorderDisabled(MCB); |
768 | |
769 | MCContext &Ctx = OutStreamer->getContext(); |
770 | bool Ok = HexagonMCInstrInfo::canonicalizePacket(MCII, STI: *Subtarget, Context&: Ctx, |
771 | MCB, Checker: nullptr); |
772 | assert(Ok); (void)Ok; |
773 | if (HexagonMCInstrInfo::bundleSize(MCI: MCB) == 0) |
774 | return; |
775 | OutStreamer->emitInstruction(Inst: MCB, STI: getSubtargetInfo()); |
776 | } |
777 | |
778 | void HexagonAsmPrinter::emitStartOfAsmFile(Module &M) { |
779 | if (TM.getTargetTriple().isOSBinFormatELF()) |
780 | emitAttributes(); |
781 | } |
782 | |
783 | void HexagonAsmPrinter::emitEndOfAsmFile(Module &M) { |
784 | HexagonTargetStreamer &HTS = |
785 | static_cast<HexagonTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
786 | if (TM.getTargetTriple().isOSBinFormatELF()) |
787 | HTS.finishAttributeSection(); |
788 | } |
789 | |
790 | void HexagonAsmPrinter::emitAttributes() { |
791 | HexagonTargetStreamer &HTS = |
792 | static_cast<HexagonTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
793 | HTS.emitTargetAttributes(STI: *TM.getMCSubtargetInfo()); |
794 | } |
795 | |
796 | void HexagonAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) { |
797 | static const int8_t NoopsInSledCount = 4; |
798 | // We want to emit the following pattern: |
799 | // |
800 | // .L_xray_sled_N: |
801 | // <xray_sled_base>: |
802 | // { jump .Ltmp0 } |
803 | // { nop |
804 | // nop |
805 | // nop |
806 | // nop } |
807 | // .Ltmp0: |
808 | // |
809 | // We need the 4 nop words because at runtime, we'd be patching over the |
810 | // full 5 words with the following pattern: |
811 | // |
812 | // <xray_sled_n>: |
813 | // { immext(#...) // upper 26-bits of trampoline |
814 | // r6 = ##... // lower 6-bits of trampoline |
815 | // immext(#...) // upper 26-bits of func id |
816 | // r7 = ##... } // lower 6 bits of func id |
817 | // { callr r6 } |
818 | // |
819 | // |
820 | auto CurSled = OutContext.createTempSymbol(Name: "xray_sled_" , AlwaysAddSuffix: true); |
821 | OutStreamer->emitLabel(Symbol: CurSled); |
822 | |
823 | MCInst *SledJump = new (OutContext) MCInst(); |
824 | SledJump->setOpcode(Hexagon::J2_jump); |
825 | auto PostSled = OutContext.createTempSymbol(); |
826 | SledJump->addOperand(Op: MCOperand::createExpr(Val: HexagonMCExpr::create( |
827 | Expr: MCSymbolRefExpr::create(Symbol: PostSled, Ctx&: OutContext), Ctx&: OutContext))); |
828 | |
829 | // Emit "jump PostSled" instruction, which jumps over the nop series. |
830 | MCInst SledJumpPacket; |
831 | SledJumpPacket.setOpcode(Hexagon::BUNDLE); |
832 | SledJumpPacket.addOperand(Op: MCOperand::createImm(Val: 0)); |
833 | SledJumpPacket.addOperand(Op: MCOperand::createInst(Val: SledJump)); |
834 | |
835 | EmitToStreamer(S&: *OutStreamer, Inst: SledJumpPacket); |
836 | |
837 | // FIXME: this will emit individual packets, we should |
838 | // special-case this and combine them into a single packet. |
839 | emitNops(N: NoopsInSledCount); |
840 | |
841 | OutStreamer->emitLabel(Symbol: PostSled); |
842 | recordSled(Sled: CurSled, MI, Kind, Version: 2); |
843 | } |
844 | |
845 | void HexagonAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) { |
846 | EmitSled(MI, Kind: SledKind::FUNCTION_ENTER); |
847 | } |
848 | |
849 | void HexagonAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) { |
850 | EmitSled(MI, Kind: SledKind::FUNCTION_EXIT); |
851 | } |
852 | |
853 | void HexagonAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) { |
854 | EmitSled(MI, Kind: SledKind::TAIL_CALL); |
855 | } |
856 | |
857 | char HexagonAsmPrinter::ID = 0; |
858 | |
859 | INITIALIZE_PASS(HexagonAsmPrinter, "hexagon-asm-printer" , |
860 | "Hexagon Assembly Printer" , false, false) |
861 | |
862 | extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void |
863 | LLVMInitializeHexagonAsmPrinter() { |
864 | RegisterAsmPrinter<HexagonAsmPrinter> X(getTheHexagonTarget()); |
865 | } |
866 | |