| //===- HexagonAsmPrinter.cpp - Print machine instrs to Hexagon assembly ---===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains a printer that converts from our internal representation |
| // of machine-dependent LLVM code to Hexagon assembly language. This printer is |
| // the output mechanism used by `llc'. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "HexagonAsmPrinter.h" |
| #include "Hexagon.h" |
| #include "HexagonInstrInfo.h" |
| #include "HexagonRegisterInfo.h" |
| #include "HexagonSubtarget.h" |
| #include "MCTargetDesc/HexagonInstPrinter.h" |
| #include "MCTargetDesc/HexagonMCExpr.h" |
| #include "MCTargetDesc/HexagonMCInstrInfo.h" |
| #include "MCTargetDesc/HexagonMCTargetDesc.h" |
| #include "TargetInfo/HexagonTargetInfo.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/BinaryFormat/ELF.h" |
| #include "llvm/CodeGen/AsmPrinter.h" |
| #include "llvm/CodeGen/MachineBasicBlock.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/CodeGen/MachineInstr.h" |
| #include "llvm/CodeGen/MachineOperand.h" |
| #include "llvm/CodeGen/TargetRegisterInfo.h" |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCDirectives.h" |
| #include "llvm/MC/MCExpr.h" |
| #include "llvm/MC/MCInst.h" |
| #include "llvm/MC/MCRegisterInfo.h" |
| #include "llvm/MC/MCSectionELF.h" |
| #include "llvm/MC/MCStreamer.h" |
| #include "llvm/MC/MCSymbol.h" |
| #include "llvm/MC/TargetRegistry.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <cstdint> |
| #include <string> |
| |
| using namespace llvm; |
| |
| namespace llvm { |
| |
| void HexagonLowerToMC(const MCInstrInfo &MCII, const MachineInstr *MI, |
| MCInst &MCB, HexagonAsmPrinter &AP); |
| |
| } // end namespace llvm |
| |
| #define DEBUG_TYPE "asm-printer" |
| |
| // Given a scalar register return its pair. |
| inline static unsigned getHexagonRegisterPair(unsigned Reg, |
| const MCRegisterInfo *RI) { |
| assert(Hexagon::IntRegsRegClass.contains(Reg)); |
| MCSuperRegIterator SR(Reg, RI, false); |
| unsigned Pair = *SR; |
| assert(Hexagon::DoubleRegsRegClass.contains(Pair)); |
| return Pair; |
| } |
| |
| void HexagonAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, |
| raw_ostream &O) { |
| const MachineOperand &MO = MI->getOperand(OpNo); |
| |
| switch (MO.getType()) { |
| default: |
| llvm_unreachable ("<unknown operand type>"); |
| case MachineOperand::MO_Register: |
| O << HexagonInstPrinter::getRegisterName(MO.getReg()); |
| return; |
| case MachineOperand::MO_Immediate: |
| O << MO.getImm(); |
| return; |
| case MachineOperand::MO_MachineBasicBlock: |
| MO.getMBB()->getSymbol()->print(O, MAI); |
| return; |
| case MachineOperand::MO_ConstantPoolIndex: |
| GetCPISymbol(MO.getIndex())->print(O, MAI); |
| return; |
| case MachineOperand::MO_GlobalAddress: |
| PrintSymbolOperand(MO, O); |
| return; |
| } |
| } |
| |
| // isBlockOnlyReachableByFallthrough - We need to override this since the |
| // default AsmPrinter does not print labels for any basic block that |
| // is only reachable by a fall through. That works for all cases except |
| // for the case in which the basic block is reachable by a fall through but |
| // through an indirect from a jump table. In this case, the jump table |
| // will contain a label not defined by AsmPrinter. |
| bool HexagonAsmPrinter::isBlockOnlyReachableByFallthrough( |
| const MachineBasicBlock *MBB) const { |
| if (MBB->hasAddressTaken()) |
| return false; |
| return AsmPrinter::isBlockOnlyReachableByFallthrough(MBB); |
| } |
| |
| /// PrintAsmOperand - Print out an operand for an inline asm expression. |
| bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
| const char *ExtraCode, |
| raw_ostream &OS) { |
| // Does this asm operand have a single letter operand modifier? |
| if (ExtraCode && ExtraCode[0]) { |
| if (ExtraCode[1] != 0) |
| return true; // Unknown modifier. |
| |
| switch (ExtraCode[0]) { |
| default: |
| // See if this is a generic print operand |
| return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS); |
| case 'L': |
| case 'H': { // The highest-numbered register of a pair. |
| const MachineOperand &MO = MI->getOperand(OpNo); |
| const MachineFunction &MF = *MI->getParent()->getParent(); |
| const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); |
| if (!MO.isReg()) |
| return true; |
| Register RegNumber = MO.getReg(); |
| // This should be an assert in the frontend. |
| if (Hexagon::DoubleRegsRegClass.contains(RegNumber)) |
| RegNumber = TRI->getSubReg(RegNumber, ExtraCode[0] == 'L' ? |
| Hexagon::isub_lo : |
| Hexagon::isub_hi); |
| OS << HexagonInstPrinter::getRegisterName(RegNumber); |
| return false; |
| } |
| case 'I': |
| // Write 'i' if an integer constant, otherwise nothing. Used to print |
| // addi vs add, etc. |
| if (MI->getOperand(OpNo).isImm()) |
| OS << "i"; |
| return false; |
| } |
| } |
| |
| printOperand(MI, OpNo, OS); |
| return false; |
| } |
| |
| bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
| unsigned OpNo, |
| const char *ExtraCode, |
| raw_ostream &O) { |
| if (ExtraCode && ExtraCode[0]) |
| return true; // Unknown modifier. |
| |
| const MachineOperand &Base = MI->getOperand(OpNo); |
| const MachineOperand &Offset = MI->getOperand(OpNo+1); |
| |
| if (Base.isReg()) |
| printOperand(MI, OpNo, O); |
| else |
| llvm_unreachable("Unimplemented"); |
| |
| if (Offset.isImm()) { |
| if (Offset.getImm()) |
| O << "+#" << Offset.getImm(); |
| } else { |
| llvm_unreachable("Unimplemented"); |
| } |
| |
| return false; |
| } |
| |
| static MCSymbol *smallData(AsmPrinter &AP, const MachineInstr &MI, |
| MCStreamer &OutStreamer, const MCOperand &Imm, |
| int AlignSize, const MCSubtargetInfo& STI) { |
| MCSymbol *Sym; |
| int64_t Value; |
| if (Imm.getExpr()->evaluateAsAbsolute(Value)) { |
| StringRef sectionPrefix; |
| std::string ImmString; |
| StringRef Name; |
| if (AlignSize == 8) { |
| Name = ".CONST_0000000000000000"; |
| sectionPrefix = ".gnu.linkonce.l8"; |
| ImmString = utohexstr(Value); |
| } else { |
| Name = ".CONST_00000000"; |
| sectionPrefix = ".gnu.linkonce.l4"; |
| ImmString = utohexstr(static_cast<uint32_t>(Value)); |
| } |
| |
| std::string symbolName = // Yes, leading zeros are kept. |
| Name.drop_back(ImmString.size()).str() + ImmString; |
| std::string sectionName = sectionPrefix.str() + symbolName; |
| |
| MCSectionELF *Section = OutStreamer.getContext().getELFSection( |
| sectionName, ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); |
| OutStreamer.SwitchSection(Section); |
| |
| Sym = AP.OutContext.getOrCreateSymbol(Twine(symbolName)); |
| if (Sym->isUndefined()) { |
| OutStreamer.emitLabel(Sym); |
| OutStreamer.emitSymbolAttribute(Sym, MCSA_Global); |
| OutStreamer.emitIntValue(Value, AlignSize); |
| OutStreamer.emitCodeAlignment(AlignSize, &STI); |
| } |
| } else { |
| assert(Imm.isExpr() && "Expected expression and found none"); |
| const MachineOperand &MO = MI.getOperand(1); |
| assert(MO.isGlobal() || MO.isCPI() || MO.isJTI()); |
| MCSymbol *MOSymbol = nullptr; |
| if (MO.isGlobal()) |
| MOSymbol = AP.getSymbol(MO.getGlobal()); |
| else if (MO.isCPI()) |
| MOSymbol = AP.GetCPISymbol(MO.getIndex()); |
| else if (MO.isJTI()) |
| MOSymbol = AP.GetJTISymbol(MO.getIndex()); |
| else |
| llvm_unreachable("Unknown operand type!"); |
| |
| StringRef SymbolName = MOSymbol->getName(); |
| std::string LitaName = ".CONST_" + SymbolName.str(); |
| |
| MCSectionELF *Section = OutStreamer.getContext().getELFSection( |
| ".lita", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); |
| |
| OutStreamer.SwitchSection(Section); |
| Sym = AP.OutContext.getOrCreateSymbol(Twine(LitaName)); |
| if (Sym->isUndefined()) { |
| OutStreamer.emitLabel(Sym); |
| OutStreamer.emitSymbolAttribute(Sym, MCSA_Local); |
| OutStreamer.emitValue(Imm.getExpr(), AlignSize); |
| OutStreamer.emitCodeAlignment(AlignSize, &STI); |
| } |
| } |
| return Sym; |
| } |
| |
| static MCInst ScaleVectorOffset(MCInst &Inst, unsigned OpNo, |
| unsigned VectorSize, MCContext &Ctx) { |
| MCInst T; |
| T.setOpcode(Inst.getOpcode()); |
| for (unsigned i = 0, n = Inst.getNumOperands(); i != n; ++i) { |
| if (i != OpNo) { |
| T.addOperand(Inst.getOperand(i)); |
| continue; |
| } |
| MCOperand &ImmOp = Inst.getOperand(i); |
| const auto *HE = static_cast<const HexagonMCExpr*>(ImmOp.getExpr()); |
| int32_t V = cast<MCConstantExpr>(HE->getExpr())->getValue(); |
| auto *NewCE = MCConstantExpr::create(V / int32_t(VectorSize), Ctx); |
| auto *NewHE = HexagonMCExpr::create(NewCE, Ctx); |
| T.addOperand(MCOperand::createExpr(NewHE)); |
| } |
| return T; |
| } |
| |
| void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst, |
| const MachineInstr &MI) { |
| MCInst &MappedInst = static_cast <MCInst &>(Inst); |
| const MCRegisterInfo *RI = OutStreamer->getContext().getRegisterInfo(); |
| const MachineFunction &MF = *MI.getParent()->getParent(); |
| auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); |
| unsigned VectorSize = HRI.getRegSizeInBits(Hexagon::HvxVRRegClass) / 8; |
| |
| switch (Inst.getOpcode()) { |
| default: |
| return; |
| |
| case Hexagon::A2_iconst: { |
| Inst.setOpcode(Hexagon::A2_addi); |
| MCOperand Reg = Inst.getOperand(0); |
| MCOperand S16 = Inst.getOperand(1); |
| HexagonMCInstrInfo::setMustNotExtend(*S16.getExpr()); |
| HexagonMCInstrInfo::setS27_2_reloc(*S16.getExpr()); |
| Inst.clear(); |
| Inst.addOperand(Reg); |
| Inst.addOperand(MCOperand::createReg(Hexagon::R0)); |
| Inst.addOperand(S16); |
| break; |
| } |
| |
| case Hexagon::A2_tfrf: { |
| const MCConstantExpr *Zero = MCConstantExpr::create(0, OutContext); |
| Inst.setOpcode(Hexagon::A2_paddif); |
| Inst.addOperand(MCOperand::createExpr(Zero)); |
| break; |
| } |
| |
| case Hexagon::A2_tfrt: { |
| const MCConstantExpr *Zero = MCConstantExpr::create(0, OutContext); |
| Inst.setOpcode(Hexagon::A2_paddit); |
| Inst.addOperand(MCOperand::createExpr(Zero)); |
| break; |
| } |
| |
| case Hexagon::A2_tfrfnew: { |
| const MCConstantExpr *Zero = MCConstantExpr::create(0, OutContext); |
| Inst.setOpcode(Hexagon::A2_paddifnew); |
| Inst.addOperand(MCOperand::createExpr(Zero)); |
| break; |
| } |
| |
| case Hexagon::A2_tfrtnew: { |
| const MCConstantExpr *Zero = MCConstantExpr::create(0, OutContext); |
| Inst.setOpcode(Hexagon::A2_padditnew); |
| Inst.addOperand(MCOperand::createExpr(Zero)); |
| break; |
| } |
| |
| case Hexagon::A2_zxtb: { |
| const MCConstantExpr *C255 = MCConstantExpr::create(255, OutContext); |
| Inst.setOpcode(Hexagon::A2_andir); |
| Inst.addOperand(MCOperand::createExpr(C255)); |
| break; |
| } |
| |
| // "$dst = CONST64(#$src1)", |
| case Hexagon::CONST64: |
| if (!OutStreamer->hasRawTextSupport()) { |
| const MCOperand &Imm = MappedInst.getOperand(1); |
| MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
| |
| MCSymbol *Sym = |
| smallData(*this, MI, *OutStreamer, Imm, 8, getSubtargetInfo()); |
| |
| OutStreamer->SwitchSection(Current.first, Current.second); |
| MCInst TmpInst; |
| MCOperand &Reg = MappedInst.getOperand(0); |
| TmpInst.setOpcode(Hexagon::L2_loadrdgp); |
| TmpInst.addOperand(Reg); |
| TmpInst.addOperand(MCOperand::createExpr( |
| MCSymbolRefExpr::create(Sym, OutContext))); |
| MappedInst = TmpInst; |
| |
| } |
| break; |
| case Hexagon::CONST32: |
| if (!OutStreamer->hasRawTextSupport()) { |
| MCOperand &Imm = MappedInst.getOperand(1); |
| MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
| MCSymbol *Sym = |
| smallData(*this, MI, *OutStreamer, Imm, 4, getSubtargetInfo()); |
| OutStreamer->SwitchSection(Current.first, Current.second); |
| MCInst TmpInst; |
| MCOperand &Reg = MappedInst.getOperand(0); |
| TmpInst.setOpcode(Hexagon::L2_loadrigp); |
| TmpInst.addOperand(Reg); |
| TmpInst.addOperand(MCOperand::createExpr(HexagonMCExpr::create( |
| MCSymbolRefExpr::create(Sym, OutContext), OutContext))); |
| MappedInst = TmpInst; |
| } |
| break; |
| |
| // C2_pxfer_map maps to C2_or instruction. Though, it's possible to use |
| // C2_or during instruction selection itself but it results |
| // into suboptimal code. |
| case Hexagon::C2_pxfer_map: { |
| MCOperand &Ps = Inst.getOperand(1); |
| MappedInst.setOpcode(Hexagon::C2_or); |
| MappedInst.addOperand(Ps); |
| return; |
| } |
| |
| // Vector reduce complex multiply by scalar, Rt & 1 map to :hi else :lo |
| // The insn is mapped from the 4 operand to the 3 operand raw form taking |
| // 3 register pairs. |
| case Hexagon::M2_vrcmpys_acc_s1: { |
| MCOperand &Rt = Inst.getOperand(3); |
| assert(Rt.isReg() && "Expected register and none was found"); |
| unsigned Reg = RI->getEncodingValue(Rt.getReg()); |
| if (Reg & 1) |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_h); |
| else |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_l); |
| Rt.setReg(getHexagonRegisterPair(Rt.getReg(), RI)); |
| return; |
| } |
| case Hexagon::M2_vrcmpys_s1: { |
| MCOperand &Rt = Inst.getOperand(2); |
| assert(Rt.isReg() && "Expected register and none was found"); |
| unsigned Reg = RI->getEncodingValue(Rt.getReg()); |
| if (Reg & 1) |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1_h); |
| else |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1_l); |
| Rt.setReg(getHexagonRegisterPair(Rt.getReg(), RI)); |
| return; |
| } |
| |
| case Hexagon::M2_vrcmpys_s1rp: { |
| MCOperand &Rt = Inst.getOperand(2); |
| assert(Rt.isReg() && "Expected register and none was found"); |
| unsigned Reg = RI->getEncodingValue(Rt.getReg()); |
| if (Reg & 1) |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1rp_h); |
| else |
| MappedInst.setOpcode(Hexagon::M2_vrcmpys_s1rp_l); |
| Rt.setReg(getHexagonRegisterPair(Rt.getReg(), RI)); |
| return; |
| } |
| |
| case Hexagon::A4_boundscheck: { |
| MCOperand &Rs = Inst.getOperand(1); |
| assert(Rs.isReg() && "Expected register and none was found"); |
| unsigned Reg = RI->getEncodingValue(Rs.getReg()); |
| if (Reg & 1) // Odd mapped to raw:hi, regpair is rodd:odd-1, like r3:2 |
| MappedInst.setOpcode(Hexagon::A4_boundscheck_hi); |
| else // raw:lo |
| MappedInst.setOpcode(Hexagon::A4_boundscheck_lo); |
| Rs.setReg(getHexagonRegisterPair(Rs.getReg(), RI)); |
| return; |
| } |
| |
| case Hexagon::PS_call_nr: |
| Inst.setOpcode(Hexagon::J2_call); |
| break; |
| |
| case Hexagon::S5_asrhub_rnd_sat_goodsyntax: { |
| MCOperand &MO = MappedInst.getOperand(2); |
| int64_t Imm; |
| MCExpr const *Expr = MO.getExpr(); |
| bool Success = Expr->evaluateAsAbsolute(Imm); |
| assert(Success && "Expected immediate and none was found"); |
| (void)Success; |
| MCInst TmpInst; |
| if (Imm == 0) { |
| TmpInst.setOpcode(Hexagon::S2_vsathub); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| TmpInst.addOperand(MappedInst.getOperand(1)); |
| MappedInst = TmpInst; |
| return; |
| } |
| TmpInst.setOpcode(Hexagon::S5_asrhub_rnd_sat); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| TmpInst.addOperand(MappedInst.getOperand(1)); |
| const MCExpr *One = MCConstantExpr::create(1, OutContext); |
| const MCExpr *Sub = MCBinaryExpr::createSub(Expr, One, OutContext); |
| TmpInst.addOperand( |
| MCOperand::createExpr(HexagonMCExpr::create(Sub, OutContext))); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| case Hexagon::S5_vasrhrnd_goodsyntax: |
| case Hexagon::S2_asr_i_p_rnd_goodsyntax: { |
| MCOperand &MO2 = MappedInst.getOperand(2); |
| MCExpr const *Expr = MO2.getExpr(); |
| int64_t Imm; |
| bool Success = Expr->evaluateAsAbsolute(Imm); |
| assert(Success && "Expected immediate and none was found"); |
| (void)Success; |
| MCInst TmpInst; |
| if (Imm == 0) { |
| TmpInst.setOpcode(Hexagon::A2_combinew); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| MCOperand &MO1 = MappedInst.getOperand(1); |
| unsigned High = RI->getSubReg(MO1.getReg(), Hexagon::isub_hi); |
| unsigned Low = RI->getSubReg(MO1.getReg(), Hexagon::isub_lo); |
| // Add a new operand for the second register in the pair. |
| TmpInst.addOperand(MCOperand::createReg(High)); |
| TmpInst.addOperand(MCOperand::createReg(Low)); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| if (Inst.getOpcode() == Hexagon::S2_asr_i_p_rnd_goodsyntax) |
| TmpInst.setOpcode(Hexagon::S2_asr_i_p_rnd); |
| else |
| TmpInst.setOpcode(Hexagon::S5_vasrhrnd); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| TmpInst.addOperand(MappedInst.getOperand(1)); |
| const MCExpr *One = MCConstantExpr::create(1, OutContext); |
| const MCExpr *Sub = MCBinaryExpr::createSub(Expr, One, OutContext); |
| TmpInst.addOperand( |
| MCOperand::createExpr(HexagonMCExpr::create(Sub, OutContext))); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| // if ("#u5==0") Assembler mapped to: "Rd=Rs"; else Rd=asr(Rs,#u5-1):rnd |
| case Hexagon::S2_asr_i_r_rnd_goodsyntax: { |
| MCOperand &MO = Inst.getOperand(2); |
| MCExpr const *Expr = MO.getExpr(); |
| int64_t Imm; |
| bool Success = Expr->evaluateAsAbsolute(Imm); |
| assert(Success && "Expected immediate and none was found"); |
| (void)Success; |
| MCInst TmpInst; |
| if (Imm == 0) { |
| TmpInst.setOpcode(Hexagon::A2_tfr); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| TmpInst.addOperand(MappedInst.getOperand(1)); |
| MappedInst = TmpInst; |
| return; |
| } |
| TmpInst.setOpcode(Hexagon::S2_asr_i_r_rnd); |
| TmpInst.addOperand(MappedInst.getOperand(0)); |
| TmpInst.addOperand(MappedInst.getOperand(1)); |
| const MCExpr *One = MCConstantExpr::create(1, OutContext); |
| const MCExpr *Sub = MCBinaryExpr::createSub(Expr, One, OutContext); |
| TmpInst.addOperand( |
| MCOperand::createExpr(HexagonMCExpr::create(Sub, OutContext))); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| // Translate a "$Rdd = #imm" to "$Rdd = combine(#[-1,0], #imm)" |
| case Hexagon::A2_tfrpi: { |
| MCInst TmpInst; |
| MCOperand &Rdd = MappedInst.getOperand(0); |
| MCOperand &MO = MappedInst.getOperand(1); |
| |
| TmpInst.setOpcode(Hexagon::A2_combineii); |
| TmpInst.addOperand(Rdd); |
| int64_t Imm; |
| bool Success = MO.getExpr()->evaluateAsAbsolute(Imm); |
| if (Success && Imm < 0) { |
| const MCExpr *MOne = MCConstantExpr::create(-1, OutContext); |
| const HexagonMCExpr *E = HexagonMCExpr::create(MOne, OutContext); |
| TmpInst.addOperand(MCOperand::createExpr(E)); |
| } else { |
| const MCExpr *Zero = MCConstantExpr::create(0, OutContext); |
| const HexagonMCExpr *E = HexagonMCExpr::create(Zero, OutContext); |
| TmpInst.addOperand(MCOperand::createExpr(E)); |
| } |
| TmpInst.addOperand(MO); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| // Translate a "$Rdd = $Rss" to "$Rdd = combine($Rs, $Rt)" |
| case Hexagon::A2_tfrp: { |
| MCOperand &MO = MappedInst.getOperand(1); |
| unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi); |
| unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo); |
| MO.setReg(High); |
| // Add a new operand for the second register in the pair. |
| MappedInst.addOperand(MCOperand::createReg(Low)); |
| MappedInst.setOpcode(Hexagon::A2_combinew); |
| return; |
| } |
| |
| case Hexagon::A2_tfrpt: |
| case Hexagon::A2_tfrpf: { |
| MCOperand &MO = MappedInst.getOperand(2); |
| unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi); |
| unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo); |
| MO.setReg(High); |
| // Add a new operand for the second register in the pair. |
| MappedInst.addOperand(MCOperand::createReg(Low)); |
| MappedInst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrpt) |
| ? Hexagon::C2_ccombinewt |
| : Hexagon::C2_ccombinewf); |
| return; |
| } |
| |
| case Hexagon::A2_tfrptnew: |
| case Hexagon::A2_tfrpfnew: { |
| MCOperand &MO = MappedInst.getOperand(2); |
| unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi); |
| unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo); |
| MO.setReg(High); |
| // Add a new operand for the second register in the pair. |
| MappedInst.addOperand(MCOperand::createReg(Low)); |
| MappedInst.setOpcode(Inst.getOpcode() == Hexagon::A2_tfrptnew |
| ? Hexagon::C2_ccombinewnewt |
| : Hexagon::C2_ccombinewnewf); |
| return; |
| } |
| |
| case Hexagon::M2_mpysmi: { |
| MCOperand &Imm = MappedInst.getOperand(2); |
| MCExpr const *Expr = Imm.getExpr(); |
| int64_t Value; |
| bool Success = Expr->evaluateAsAbsolute(Value); |
| assert(Success); |
| (void)Success; |
| if (Value < 0 && Value > -256) { |
| MappedInst.setOpcode(Hexagon::M2_mpysin); |
| Imm.setExpr(HexagonMCExpr::create( |
| MCUnaryExpr::createMinus(Expr, OutContext), OutContext)); |
| } else |
| MappedInst.setOpcode(Hexagon::M2_mpysip); |
| return; |
| } |
| |
| case Hexagon::A2_addsp: { |
| MCOperand &Rt = Inst.getOperand(1); |
| assert(Rt.isReg() && "Expected register and none was found"); |
| unsigned Reg = RI->getEncodingValue(Rt.getReg()); |
| if (Reg & 1) |
| MappedInst.setOpcode(Hexagon::A2_addsph); |
| else |
| MappedInst.setOpcode(Hexagon::A2_addspl); |
| Rt.setReg(getHexagonRegisterPair(Rt.getReg(), RI)); |
| return; |
| } |
| |
| case Hexagon::V6_vd0: { |
| MCInst TmpInst; |
| assert(Inst.getOperand(0).isReg() && |
| "Expected register and none was found"); |
| |
| TmpInst.setOpcode(Hexagon::V6_vxor); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| case Hexagon::V6_vdd0: { |
| MCInst TmpInst; |
| assert (Inst.getOperand(0).isReg() && |
| "Expected register and none was found"); |
| |
| TmpInst.setOpcode(Hexagon::V6_vsubw_dv); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| TmpInst.addOperand(Inst.getOperand(0)); |
| MappedInst = TmpInst; |
| return; |
| } |
| |
| case Hexagon::V6_vL32Ub_pi: |
| case Hexagon::V6_vL32b_cur_pi: |
| case Hexagon::V6_vL32b_nt_cur_pi: |
| case Hexagon::V6_vL32b_pi: |
| case Hexagon::V6_vL32b_nt_pi: |
| case Hexagon::V6_vL32b_nt_tmp_pi: |
| case Hexagon::V6_vL32b_tmp_pi: |
| MappedInst = ScaleVectorOffset(Inst, 3, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vL32Ub_ai: |
| case Hexagon::V6_vL32b_ai: |
| case Hexagon::V6_vL32b_cur_ai: |
| case Hexagon::V6_vL32b_nt_ai: |
| case Hexagon::V6_vL32b_nt_cur_ai: |
| case Hexagon::V6_vL32b_nt_tmp_ai: |
| case Hexagon::V6_vL32b_tmp_ai: |
| MappedInst = ScaleVectorOffset(Inst, 2, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vS32Ub_pi: |
| case Hexagon::V6_vS32b_new_pi: |
| case Hexagon::V6_vS32b_nt_new_pi: |
| case Hexagon::V6_vS32b_nt_pi: |
| case Hexagon::V6_vS32b_pi: |
| MappedInst = ScaleVectorOffset(Inst, 2, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vS32Ub_ai: |
| case Hexagon::V6_vS32b_ai: |
| case Hexagon::V6_vS32b_new_ai: |
| case Hexagon::V6_vS32b_nt_ai: |
| case Hexagon::V6_vS32b_nt_new_ai: |
| MappedInst = ScaleVectorOffset(Inst, 1, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vL32b_cur_npred_pi: |
| case Hexagon::V6_vL32b_cur_pred_pi: |
| case Hexagon::V6_vL32b_npred_pi: |
| case Hexagon::V6_vL32b_nt_cur_npred_pi: |
| case Hexagon::V6_vL32b_nt_cur_pred_pi: |
| case Hexagon::V6_vL32b_nt_npred_pi: |
| case Hexagon::V6_vL32b_nt_pred_pi: |
| case Hexagon::V6_vL32b_nt_tmp_npred_pi: |
| case Hexagon::V6_vL32b_nt_tmp_pred_pi: |
| case Hexagon::V6_vL32b_pred_pi: |
| case Hexagon::V6_vL32b_tmp_npred_pi: |
| case Hexagon::V6_vL32b_tmp_pred_pi: |
| MappedInst = ScaleVectorOffset(Inst, 4, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vL32b_cur_npred_ai: |
| case Hexagon::V6_vL32b_cur_pred_ai: |
| case Hexagon::V6_vL32b_npred_ai: |
| case Hexagon::V6_vL32b_nt_cur_npred_ai: |
| case Hexagon::V6_vL32b_nt_cur_pred_ai: |
| case Hexagon::V6_vL32b_nt_npred_ai: |
| case Hexagon::V6_vL32b_nt_pred_ai: |
| case Hexagon::V6_vL32b_nt_tmp_npred_ai: |
| case Hexagon::V6_vL32b_nt_tmp_pred_ai: |
| case Hexagon::V6_vL32b_pred_ai: |
| case Hexagon::V6_vL32b_tmp_npred_ai: |
| case Hexagon::V6_vL32b_tmp_pred_ai: |
| MappedInst = ScaleVectorOffset(Inst, 3, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vS32Ub_npred_pi: |
| case Hexagon::V6_vS32Ub_pred_pi: |
| case Hexagon::V6_vS32b_new_npred_pi: |
| case Hexagon::V6_vS32b_new_pred_pi: |
| case Hexagon::V6_vS32b_npred_pi: |
| case Hexagon::V6_vS32b_nqpred_pi: |
| case Hexagon::V6_vS32b_nt_new_npred_pi: |
| case Hexagon::V6_vS32b_nt_new_pred_pi: |
| case Hexagon::V6_vS32b_nt_npred_pi: |
| case Hexagon::V6_vS32b_nt_nqpred_pi: |
| case Hexagon::V6_vS32b_nt_pred_pi: |
| case Hexagon::V6_vS32b_nt_qpred_pi: |
| case Hexagon::V6_vS32b_pred_pi: |
| case Hexagon::V6_vS32b_qpred_pi: |
| MappedInst = ScaleVectorOffset(Inst, 3, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vS32Ub_npred_ai: |
| case Hexagon::V6_vS32Ub_pred_ai: |
| case Hexagon::V6_vS32b_new_npred_ai: |
| case Hexagon::V6_vS32b_new_pred_ai: |
| case Hexagon::V6_vS32b_npred_ai: |
| case Hexagon::V6_vS32b_nqpred_ai: |
| case Hexagon::V6_vS32b_nt_new_npred_ai: |
| case Hexagon::V6_vS32b_nt_new_pred_ai: |
| case Hexagon::V6_vS32b_nt_npred_ai: |
| case Hexagon::V6_vS32b_nt_nqpred_ai: |
| case Hexagon::V6_vS32b_nt_pred_ai: |
| case Hexagon::V6_vS32b_nt_qpred_ai: |
| case Hexagon::V6_vS32b_pred_ai: |
| case Hexagon::V6_vS32b_qpred_ai: |
| MappedInst = ScaleVectorOffset(Inst, 2, VectorSize, OutContext); |
| return; |
| |
| // V65+ |
| case Hexagon::V6_vS32b_srls_ai: |
| MappedInst = ScaleVectorOffset(Inst, 1, VectorSize, OutContext); |
| return; |
| |
| case Hexagon::V6_vS32b_srls_pi: |
| MappedInst = ScaleVectorOffset(Inst, 2, VectorSize, OutContext); |
| return; |
| } |
| } |
| |
| /// Print out a single Hexagon MI to the current output stream. |
| void HexagonAsmPrinter::emitInstruction(const MachineInstr *MI) { |
| MCInst MCB; |
| MCB.setOpcode(Hexagon::BUNDLE); |
| MCB.addOperand(MCOperand::createImm(0)); |
| const MCInstrInfo &MCII = *Subtarget->getInstrInfo(); |
| |
| if (MI->isBundle()) { |
| const MachineBasicBlock* MBB = MI->getParent(); |
| MachineBasicBlock::const_instr_iterator MII = MI->getIterator(); |
| |
| for (++MII; MII != MBB->instr_end() && MII->isInsideBundle(); ++MII) |
| if (!MII->isDebugInstr() && !MII->isImplicitDef()) |
| HexagonLowerToMC(MCII, &*MII, MCB, *this); |
| } else { |
| HexagonLowerToMC(MCII, MI, MCB, *this); |
| } |
| |
| const MachineFunction &MF = *MI->getParent()->getParent(); |
| const auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); |
| if (MI->isBundle() && HII.getBundleNoShuf(*MI)) |
| HexagonMCInstrInfo::setMemReorderDisabled(MCB); |
| |
| MCContext &Ctx = OutStreamer->getContext(); |
| bool Ok = HexagonMCInstrInfo::canonicalizePacket(MCII, *Subtarget, Ctx, |
| MCB, nullptr); |
| assert(Ok); (void)Ok; |
| if (HexagonMCInstrInfo::bundleSize(MCB) == 0) |
| return; |
| OutStreamer->emitInstruction(MCB, getSubtargetInfo()); |
| } |
| |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeHexagonAsmPrinter() { |
| RegisterAsmPrinter<HexagonAsmPrinter> X(getTheHexagonTarget()); |
| } |