| 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 | |