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