//===- lib/CodeGen/MachineOperand.cpp -------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // /// \file Methods common to all machine operands. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/MachineOperand.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/CodeGen/MIRPrinter.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/MC/MCDwarf.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; static cl::opt PrintRegMaskNumRegs("print-regmask-num-regs", cl::desc("Number of registers to limit to when " "printing regmask operands in IR dumps. " "unlimited = -1"), cl::init(32), cl::Hidden); static const MachineFunction *getMFIfAvailable(const MachineOperand &MO) { if (const MachineInstr *MI = MO.getParent()) if (const MachineBasicBlock *MBB = MI->getParent()) if (const MachineFunction *MF = MBB->getParent()) return MF; return nullptr; } static MachineFunction *getMFIfAvailable(MachineOperand &MO) { return const_cast( getMFIfAvailable(const_cast(MO))); } void MachineOperand::setReg(unsigned Reg) { if (getReg() == Reg) return; // No change. // Clear the IsRenamable bit to keep it conservatively correct. IsRenamable = false; // Otherwise, we have to change the register. If this operand is embedded // into a machine function, we need to update the old and new register's // use/def lists. if (MachineFunction *MF = getMFIfAvailable(*this)) { MachineRegisterInfo &MRI = MF->getRegInfo(); MRI.removeRegOperandFromUseList(this); SmallContents.RegNo = Reg; MRI.addRegOperandToUseList(this); return; } // Otherwise, just change the register, no problem. :) SmallContents.RegNo = Reg; } void MachineOperand::substVirtReg(unsigned Reg, unsigned SubIdx, const TargetRegisterInfo &TRI) { assert(TargetRegisterInfo::isVirtualRegister(Reg)); if (SubIdx && getSubReg()) SubIdx = TRI.composeSubRegIndices(SubIdx, getSubReg()); setReg(Reg); if (SubIdx) setSubReg(SubIdx); } void MachineOperand::substPhysReg(unsigned Reg, const TargetRegisterInfo &TRI) { assert(TargetRegisterInfo::isPhysicalRegister(Reg)); if (getSubReg()) { Reg = TRI.getSubReg(Reg, getSubReg()); // Note that getSubReg() may return 0 if the sub-register doesn't exist. // That won't happen in legal code. setSubReg(0); if (isDef()) setIsUndef(false); } setReg(Reg); } /// Change a def to a use, or a use to a def. void MachineOperand::setIsDef(bool Val) { assert(isReg() && "Wrong MachineOperand accessor"); assert((!Val || !isDebug()) && "Marking a debug operation as def"); if (IsDef == Val) return; assert(!IsDeadOrKill && "Changing def/use with dead/kill set not supported"); // MRI may keep uses and defs in different list positions. if (MachineFunction *MF = getMFIfAvailable(*this)) { MachineRegisterInfo &MRI = MF->getRegInfo(); MRI.removeRegOperandFromUseList(this); IsDef = Val; MRI.addRegOperandToUseList(this); return; } IsDef = Val; } bool MachineOperand::isRenamable() const { assert(isReg() && "Wrong MachineOperand accessor"); assert(TargetRegisterInfo::isPhysicalRegister(getReg()) && "isRenamable should only be checked on physical registers"); if (!IsRenamable) return false; const MachineInstr *MI = getParent(); if (!MI) return true; if (isDef()) return !MI->hasExtraDefRegAllocReq(MachineInstr::IgnoreBundle); assert(isUse() && "Reg is not def or use"); return !MI->hasExtraSrcRegAllocReq(MachineInstr::IgnoreBundle); } void MachineOperand::setIsRenamable(bool Val) { assert(isReg() && "Wrong MachineOperand accessor"); assert(TargetRegisterInfo::isPhysicalRegister(getReg()) && "setIsRenamable should only be called on physical registers"); IsRenamable = Val; } // If this operand is currently a register operand, and if this is in a // function, deregister the operand from the register's use/def list. void MachineOperand::removeRegFromUses() { if (!isReg() || !isOnRegUseList()) return; if (MachineFunction *MF = getMFIfAvailable(*this)) MF->getRegInfo().removeRegOperandFromUseList(this); } /// ChangeToImmediate - Replace this operand with a new immediate operand of /// the specified value. If an operand is known to be an immediate already, /// the setImm method should be used. void MachineOperand::ChangeToImmediate(int64_t ImmVal) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into an imm"); removeRegFromUses(); OpKind = MO_Immediate; Contents.ImmVal = ImmVal; } void MachineOperand::ChangeToFPImmediate(const ConstantFP *FPImm) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into an imm"); removeRegFromUses(); OpKind = MO_FPImmediate; Contents.CFP = FPImm; } void MachineOperand::ChangeToES(const char *SymName, unsigned char TargetFlags) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into an external symbol"); removeRegFromUses(); OpKind = MO_ExternalSymbol; Contents.OffsetedInfo.Val.SymbolName = SymName; setOffset(0); // Offset is always 0. setTargetFlags(TargetFlags); } void MachineOperand::ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned char TargetFlags) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into a global address"); removeRegFromUses(); OpKind = MO_GlobalAddress; Contents.OffsetedInfo.Val.GV = GV; setOffset(Offset); setTargetFlags(TargetFlags); } void MachineOperand::ChangeToMCSymbol(MCSymbol *Sym) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into an MCSymbol"); removeRegFromUses(); OpKind = MO_MCSymbol; Contents.Sym = Sym; } void MachineOperand::ChangeToFrameIndex(int Idx) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into a FrameIndex"); removeRegFromUses(); OpKind = MO_FrameIndex; setIndex(Idx); } void MachineOperand::ChangeToTargetIndex(unsigned Idx, int64_t Offset, unsigned char TargetFlags) { assert((!isReg() || !isTied()) && "Cannot change a tied operand into a FrameIndex"); removeRegFromUses(); OpKind = MO_TargetIndex; setIndex(Idx); setOffset(Offset); setTargetFlags(TargetFlags); } /// ChangeToRegister - Replace this operand with a new register operand of /// the specified value. If an operand is known to be an register already, /// the setReg method should be used. void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp, bool isKill, bool isDead, bool isUndef, bool isDebug) { MachineRegisterInfo *RegInfo = nullptr; if (MachineFunction *MF = getMFIfAvailable(*this)) RegInfo = &MF->getRegInfo(); // If this operand is already a register operand, remove it from the // register's use/def lists. bool WasReg = isReg(); if (RegInfo && WasReg) RegInfo->removeRegOperandFromUseList(this); // Change this to a register and set the reg#. assert(!(isDead && !isDef) && "Dead flag on non-def"); assert(!(isKill && isDef) && "Kill flag on def"); OpKind = MO_Register; SmallContents.RegNo = Reg; SubReg_TargetFlags = 0; IsDef = isDef; IsImp = isImp; IsDeadOrKill = isKill | isDead; IsRenamable = false; IsUndef = isUndef; IsInternalRead = false; IsEarlyClobber = false; IsDebug = isDebug; // Ensure isOnRegUseList() returns false. Contents.Reg.Prev = nullptr; // Preserve the tie when the operand was already a register. if (!WasReg) TiedTo = 0; // If this operand is embedded in a function, add the operand to the // register's use/def list. if (RegInfo) RegInfo->addRegOperandToUseList(this); } /// isIdenticalTo - Return true if this operand is identical to the specified /// operand. Note that this should stay in sync with the hash_value overload /// below. bool MachineOperand::isIdenticalTo(const MachineOperand &Other) const { if (getType() != Other.getType() || getTargetFlags() != Other.getTargetFlags()) return false; switch (getType()) { case MachineOperand::MO_Register: return getReg() == Other.getReg() && isDef() == Other.isDef() && getSubReg() == Other.getSubReg(); case MachineOperand::MO_Immediate: return getImm() == Other.getImm(); case MachineOperand::MO_CImmediate: return getCImm() == Other.getCImm(); case MachineOperand::MO_FPImmediate: return getFPImm() == Other.getFPImm(); case MachineOperand::MO_MachineBasicBlock: return getMBB() == Other.getMBB(); case MachineOperand::MO_FrameIndex: return getIndex() == Other.getIndex(); case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_TargetIndex: return getIndex() == Other.getIndex() && getOffset() == Other.getOffset(); case MachineOperand::MO_JumpTableIndex: return getIndex() == Other.getIndex(); case MachineOperand::MO_GlobalAddress: return getGlobal() == Other.getGlobal() && getOffset() == Other.getOffset(); case MachineOperand::MO_ExternalSymbol: return strcmp(getSymbolName(), Other.getSymbolName()) == 0 && getOffset() == Other.getOffset(); case MachineOperand::MO_BlockAddress: return getBlockAddress() == Other.getBlockAddress() && getOffset() == Other.getOffset(); case MachineOperand::MO_RegisterMask: case MachineOperand::MO_RegisterLiveOut: { // Shallow compare of the two RegMasks const uint32_t *RegMask = getRegMask(); const uint32_t *OtherRegMask = Other.getRegMask(); if (RegMask == OtherRegMask) return true; if (const MachineFunction *MF = getMFIfAvailable(*this)) { // Calculate the size of the RegMask const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); unsigned RegMaskSize = (TRI->getNumRegs() + 31) / 32; // Deep compare of the two RegMasks return std::equal(RegMask, RegMask + RegMaskSize, OtherRegMask); } // We don't know the size of the RegMask, so we can't deep compare the two // reg masks. return false; } case MachineOperand::MO_MCSymbol: return getMCSymbol() == Other.getMCSymbol(); case MachineOperand::MO_CFIIndex: return getCFIIndex() == Other.getCFIIndex(); case MachineOperand::MO_Metadata: return getMetadata() == Other.getMetadata(); case MachineOperand::MO_IntrinsicID: return getIntrinsicID() == Other.getIntrinsicID(); case MachineOperand::MO_Predicate: return getPredicate() == Other.getPredicate(); } llvm_unreachable("Invalid machine operand type"); } // Note: this must stay exactly in sync with isIdenticalTo above. hash_code llvm::hash_value(const MachineOperand &MO) { switch (MO.getType()) { case MachineOperand::MO_Register: // Register operands don't have target flags. return hash_combine(MO.getType(), (unsigned)MO.getReg(), MO.getSubReg(), MO.isDef()); case MachineOperand::MO_Immediate: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getImm()); case MachineOperand::MO_CImmediate: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getCImm()); case MachineOperand::MO_FPImmediate: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getFPImm()); case MachineOperand::MO_MachineBasicBlock: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getMBB()); case MachineOperand::MO_FrameIndex: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIndex()); case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_TargetIndex: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIndex(), MO.getOffset()); case MachineOperand::MO_JumpTableIndex: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIndex()); case MachineOperand::MO_ExternalSymbol: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getOffset(), StringRef(MO.getSymbolName())); case MachineOperand::MO_GlobalAddress: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getGlobal(), MO.getOffset()); case MachineOperand::MO_BlockAddress: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getBlockAddress(), MO.getOffset()); case MachineOperand::MO_RegisterMask: case MachineOperand::MO_RegisterLiveOut: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getRegMask()); case MachineOperand::MO_Metadata: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getMetadata()); case MachineOperand::MO_MCSymbol: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getMCSymbol()); case MachineOperand::MO_CFIIndex: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getCFIIndex()); case MachineOperand::MO_IntrinsicID: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIntrinsicID()); case MachineOperand::MO_Predicate: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getPredicate()); } llvm_unreachable("Invalid machine operand type"); } // Try to crawl up to the machine function and get TRI and IntrinsicInfo from // it. static void tryToGetTargetInfo(const MachineOperand &MO, const TargetRegisterInfo *&TRI, const TargetIntrinsicInfo *&IntrinsicInfo) { if (const MachineFunction *MF = getMFIfAvailable(MO)) { TRI = MF->getSubtarget().getRegisterInfo(); IntrinsicInfo = MF->getTarget().getIntrinsicInfo(); } } static const char *getTargetIndexName(const MachineFunction &MF, int Index) { const auto *TII = MF.getSubtarget().getInstrInfo(); assert(TII && "expected instruction info"); auto Indices = TII->getSerializableTargetIndices(); auto Found = find_if(Indices, [&](const std::pair &I) { return I.first == Index; }); if (Found != Indices.end()) return Found->second; return nullptr; } static const char *getTargetFlagName(const TargetInstrInfo *TII, unsigned TF) { auto Flags = TII->getSerializableDirectMachineOperandTargetFlags(); for (const auto &I : Flags) { if (I.first == TF) { return I.second; } } return nullptr; } static void printCFIRegister(unsigned DwarfReg, raw_ostream &OS, const TargetRegisterInfo *TRI) { if (!TRI) { OS << "%dwarfreg." << DwarfReg; return; } int Reg = TRI->getLLVMRegNum(DwarfReg, true); if (Reg == -1) { OS << ""; return; } OS << printReg(Reg, TRI); } static void printIRBlockReference(raw_ostream &OS, const BasicBlock &BB, ModuleSlotTracker &MST) { OS << "%ir-block."; if (BB.hasName()) { printLLVMNameWithoutPrefix(OS, BB.getName()); return; } Optional Slot; if (const Function *F = BB.getParent()) { if (F == MST.getCurrentFunction()) { Slot = MST.getLocalSlot(&BB); } else if (const Module *M = F->getParent()) { ModuleSlotTracker CustomMST(M, /*ShouldInitializeAllMetadata=*/false); CustomMST.incorporateFunction(*F); Slot = CustomMST.getLocalSlot(&BB); } } if (Slot) MachineOperand::printIRSlotNumber(OS, *Slot); else OS << ""; } static void printIRValueReference(raw_ostream &OS, const Value &V, ModuleSlotTracker &MST) { if (isa(V)) { V.printAsOperand(OS, /*PrintType=*/false, MST); return; } if (isa(V)) { // Machine memory operands can load/store to/from constant value pointers. OS << '`'; V.printAsOperand(OS, /*PrintType=*/true, MST); OS << '`'; return; } OS << "%ir."; if (V.hasName()) { printLLVMNameWithoutPrefix(OS, V.getName()); return; } int Slot = MST.getCurrentFunction() ? MST.getLocalSlot(&V) : -1; MachineOperand::printIRSlotNumber(OS, Slot); } static void printSyncScope(raw_ostream &OS, const LLVMContext &Context, SyncScope::ID SSID, SmallVectorImpl &SSNs) { switch (SSID) { case SyncScope::System: break; default: if (SSNs.empty()) Context.getSyncScopeNames(SSNs); OS << "syncscope(\""; printEscapedString(SSNs[SSID], OS); OS << "\") "; break; } } static const char *getTargetMMOFlagName(const TargetInstrInfo &TII, unsigned TMMOFlag) { auto Flags = TII.getSerializableMachineMemOperandTargetFlags(); for (const auto &I : Flags) { if (I.first == TMMOFlag) { return I.second; } } return nullptr; } static void printFrameIndex(raw_ostream& OS, int FrameIndex, bool IsFixed, const MachineFrameInfo *MFI) { StringRef Name; if (MFI) { IsFixed = MFI->isFixedObjectIndex(FrameIndex); if (const AllocaInst *Alloca = MFI->getObjectAllocation(FrameIndex)) if (Alloca->hasName()) Name = Alloca->getName(); if (IsFixed) FrameIndex -= MFI->getObjectIndexBegin(); } MachineOperand::printStackObjectReference(OS, FrameIndex, IsFixed, Name); } void MachineOperand::printSubRegIdx(raw_ostream &OS, uint64_t Index, const TargetRegisterInfo *TRI) { OS << "%subreg."; if (TRI) OS << TRI->getSubRegIndexName(Index); else OS << Index; } void MachineOperand::printTargetFlags(raw_ostream &OS, const MachineOperand &Op) { if (!Op.getTargetFlags()) return; const MachineFunction *MF = getMFIfAvailable(Op); if (!MF) return; const auto *TII = MF->getSubtarget().getInstrInfo(); assert(TII && "expected instruction info"); auto Flags = TII->decomposeMachineOperandsTargetFlags(Op.getTargetFlags()); OS << "target-flags("; const bool HasDirectFlags = Flags.first; const bool HasBitmaskFlags = Flags.second; if (!HasDirectFlags && !HasBitmaskFlags) { OS << ") "; return; } if (HasDirectFlags) { if (const auto *Name = getTargetFlagName(TII, Flags.first)) OS << Name; else OS << ""; } if (!HasBitmaskFlags) { OS << ") "; return; } bool IsCommaNeeded = HasDirectFlags; unsigned BitMask = Flags.second; auto BitMasks = TII->getSerializableBitmaskMachineOperandTargetFlags(); for (const auto &Mask : BitMasks) { // Check if the flag's bitmask has the bits of the current mask set. if ((BitMask & Mask.first) == Mask.first) { if (IsCommaNeeded) OS << ", "; IsCommaNeeded = true; OS << Mask.second; // Clear the bits which were serialized from the flag's bitmask. BitMask &= ~(Mask.first); } } if (BitMask) { // When the resulting flag's bitmask isn't zero, we know that we didn't // serialize all of the bit flags. if (IsCommaNeeded) OS << ", "; OS << ""; } OS << ") "; } void MachineOperand::printSymbol(raw_ostream &OS, MCSymbol &Sym) { OS << ""; } void MachineOperand::printStackObjectReference(raw_ostream &OS, unsigned FrameIndex, bool IsFixed, StringRef Name) { if (IsFixed) { OS << "%fixed-stack." << FrameIndex; return; } OS << "%stack." << FrameIndex; if (!Name.empty()) OS << '.' << Name; } void MachineOperand::printOperandOffset(raw_ostream &OS, int64_t Offset) { if (Offset == 0) return; if (Offset < 0) { OS << " - " << -Offset; return; } OS << " + " << Offset; } void MachineOperand::printIRSlotNumber(raw_ostream &OS, int Slot) { if (Slot == -1) OS << ""; else OS << Slot; } static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI, const TargetRegisterInfo *TRI) { switch (CFI.getOperation()) { case MCCFIInstruction::OpSameValue: OS << "same_value "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); break; case MCCFIInstruction::OpRememberState: OS << "remember_state "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); break; case MCCFIInstruction::OpRestoreState: OS << "restore_state "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); break; case MCCFIInstruction::OpOffset: OS << "offset "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); OS << ", " << CFI.getOffset(); break; case MCCFIInstruction::OpDefCfaRegister: OS << "def_cfa_register "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); break; case MCCFIInstruction::OpDefCfaOffset: OS << "def_cfa_offset "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); OS << CFI.getOffset(); break; case MCCFIInstruction::OpDefCfa: OS << "def_cfa "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); OS << ", " << CFI.getOffset(); break; case MCCFIInstruction::OpRelOffset: OS << "rel_offset "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); OS << ", " << CFI.getOffset(); break; case MCCFIInstruction::OpAdjustCfaOffset: OS << "adjust_cfa_offset "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); OS << CFI.getOffset(); break; case MCCFIInstruction::OpRestore: OS << "restore "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); break; case MCCFIInstruction::OpEscape: { OS << "escape "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); if (!CFI.getValues().empty()) { size_t e = CFI.getValues().size() - 1; for (size_t i = 0; i < e; ++i) OS << format("0x%02x", uint8_t(CFI.getValues()[i])) << ", "; OS << format("0x%02x", uint8_t(CFI.getValues()[e])) << ", "; } break; } case MCCFIInstruction::OpUndefined: OS << "undefined "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); break; case MCCFIInstruction::OpRegister: OS << "register "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); printCFIRegister(CFI.getRegister(), OS, TRI); OS << ", "; printCFIRegister(CFI.getRegister2(), OS, TRI); break; case MCCFIInstruction::OpWindowSave: OS << "window_save "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); break; case MCCFIInstruction::OpNegateRAState: OS << "negate_ra_sign_state "; if (MCSymbol *Label = CFI.getLabel()) MachineOperand::printSymbol(OS, *Label); break; default: // TODO: Print the other CFI Operations. OS << ""; break; } } void MachineOperand::print(raw_ostream &OS, const TargetRegisterInfo *TRI, const TargetIntrinsicInfo *IntrinsicInfo) const { print(OS, LLT{}, TRI, IntrinsicInfo); } void MachineOperand::print(raw_ostream &OS, LLT TypeToPrint, const TargetRegisterInfo *TRI, const TargetIntrinsicInfo *IntrinsicInfo) const { tryToGetTargetInfo(*this, TRI, IntrinsicInfo); ModuleSlotTracker DummyMST(nullptr); print(OS, DummyMST, TypeToPrint, /*PrintDef=*/false, /*IsStandalone=*/true, /*ShouldPrintRegisterTies=*/true, /*TiedOperandIdx=*/0, TRI, IntrinsicInfo); } void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST, LLT TypeToPrint, bool PrintDef, bool IsStandalone, bool ShouldPrintRegisterTies, unsigned TiedOperandIdx, const TargetRegisterInfo *TRI, const TargetIntrinsicInfo *IntrinsicInfo) const { printTargetFlags(OS, *this); switch (getType()) { case MachineOperand::MO_Register: { unsigned Reg = getReg(); if (isImplicit()) OS << (isDef() ? "implicit-def " : "implicit "); else if (PrintDef && isDef()) // Print the 'def' flag only when the operand is defined after '='. OS << "def "; if (isInternalRead()) OS << "internal "; if (isDead()) OS << "dead "; if (isKill()) OS << "killed "; if (isUndef()) OS << "undef "; if (isEarlyClobber()) OS << "early-clobber "; if (TargetRegisterInfo::isPhysicalRegister(getReg()) && isRenamable()) OS << "renamable "; // isDebug() is exactly true for register operands of a DBG_VALUE. So we // simply infer it when parsing and do not need to print it. const MachineRegisterInfo *MRI = nullptr; if (TargetRegisterInfo::isVirtualRegister(Reg)) { if (const MachineFunction *MF = getMFIfAvailable(*this)) { MRI = &MF->getRegInfo(); } } OS << printReg(Reg, TRI, 0, MRI); // Print the sub register. if (unsigned SubReg = getSubReg()) { if (TRI) OS << '.' << TRI->getSubRegIndexName(SubReg); else OS << ".subreg" << SubReg; } // Print the register class / bank. if (TargetRegisterInfo::isVirtualRegister(Reg)) { if (const MachineFunction *MF = getMFIfAvailable(*this)) { const MachineRegisterInfo &MRI = MF->getRegInfo(); if (IsStandalone || !PrintDef || MRI.def_empty(Reg)) { OS << ':'; OS << printRegClassOrBank(Reg, MRI, TRI); } } } // Print ties. if (ShouldPrintRegisterTies && isTied() && !isDef()) OS << "(tied-def " << TiedOperandIdx << ")"; // Print types. if (TypeToPrint.isValid()) OS << '(' << TypeToPrint << ')'; break; } case MachineOperand::MO_Immediate: OS << getImm(); break; case MachineOperand::MO_CImmediate: getCImm()->printAsOperand(OS, /*PrintType=*/true, MST); break; case MachineOperand::MO_FPImmediate: getFPImm()->printAsOperand(OS, /*PrintType=*/true, MST); break; case MachineOperand::MO_MachineBasicBlock: OS << printMBBReference(*getMBB()); break; case MachineOperand::MO_FrameIndex: { int FrameIndex = getIndex(); bool IsFixed = false; const MachineFrameInfo *MFI = nullptr; if (const MachineFunction *MF = getMFIfAvailable(*this)) MFI = &MF->getFrameInfo(); printFrameIndex(OS, FrameIndex, IsFixed, MFI); break; } case MachineOperand::MO_ConstantPoolIndex: OS << "%const." << getIndex(); printOperandOffset(OS, getOffset()); break; case MachineOperand::MO_TargetIndex: { OS << "target-index("; const char *Name = ""; if (const MachineFunction *MF = getMFIfAvailable(*this)) if (const auto *TargetIndexName = getTargetIndexName(*MF, getIndex())) Name = TargetIndexName; OS << Name << ')'; printOperandOffset(OS, getOffset()); break; } case MachineOperand::MO_JumpTableIndex: OS << printJumpTableEntryReference(getIndex()); break; case MachineOperand::MO_GlobalAddress: getGlobal()->printAsOperand(OS, /*PrintType=*/false, MST); printOperandOffset(OS, getOffset()); break; case MachineOperand::MO_ExternalSymbol: { StringRef Name = getSymbolName(); OS << '&'; if (Name.empty()) { OS << "\"\""; } else { printLLVMNameWithoutPrefix(OS, Name); } printOperandOffset(OS, getOffset()); break; } case MachineOperand::MO_BlockAddress: { OS << "blockaddress("; getBlockAddress()->getFunction()->printAsOperand(OS, /*PrintType=*/false, MST); OS << ", "; printIRBlockReference(OS, *getBlockAddress()->getBasicBlock(), MST); OS << ')'; MachineOperand::printOperandOffset(OS, getOffset()); break; } case MachineOperand::MO_RegisterMask: { OS << "getNumRegs(); ++i) { unsigned MaskWord = i / 32; unsigned MaskBit = i % 32; if (getRegMask()[MaskWord] & (1 << MaskBit)) { if (PrintRegMaskNumRegs < 0 || NumRegsEmitted <= static_cast(PrintRegMaskNumRegs)) { OS << " " << printReg(i, TRI); NumRegsEmitted++; } NumRegsInMask++; } } if (NumRegsEmitted != NumRegsInMask) OS << " and " << (NumRegsInMask - NumRegsEmitted) << " more..."; } else { OS << " ..."; } OS << ">"; break; } case MachineOperand::MO_RegisterLiveOut: { const uint32_t *RegMask = getRegLiveOut(); OS << "liveout("; if (!TRI) { OS << ""; } else { bool IsCommaNeeded = false; for (unsigned Reg = 0, E = TRI->getNumRegs(); Reg < E; ++Reg) { if (RegMask[Reg / 32] & (1U << (Reg % 32))) { if (IsCommaNeeded) OS << ", "; OS << printReg(Reg, TRI); IsCommaNeeded = true; } } } OS << ")"; break; } case MachineOperand::MO_Metadata: getMetadata()->printAsOperand(OS, MST); break; case MachineOperand::MO_MCSymbol: printSymbol(OS, *getMCSymbol()); break; case MachineOperand::MO_CFIIndex: { if (const MachineFunction *MF = getMFIfAvailable(*this)) printCFI(OS, MF->getFrameInstructions()[getCFIIndex()], TRI); else OS << ""; break; } case MachineOperand::MO_IntrinsicID: { Intrinsic::ID ID = getIntrinsicID(); if (ID < Intrinsic::num_intrinsics) OS << "intrinsic(@" << Intrinsic::getName(ID, None) << ')'; else if (IntrinsicInfo) OS << "intrinsic(@" << IntrinsicInfo->getName(ID) << ')'; else OS << "intrinsic(" << ID << ')'; break; } case MachineOperand::MO_Predicate: { auto Pred = static_cast(getPredicate()); OS << (CmpInst::isIntPredicate(Pred) ? "int" : "float") << "pred(" << CmpInst::getPredicateName(Pred) << ')'; break; } } } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MachineOperand::dump() const { dbgs() << *this << '\n'; } #endif //===----------------------------------------------------------------------===// // MachineMemOperand Implementation //===----------------------------------------------------------------------===// /// getAddrSpace - Return the LLVM IR address space number that this pointer /// points into. unsigned MachinePointerInfo::getAddrSpace() const { return AddrSpace; } /// isDereferenceable - Return true if V is always dereferenceable for /// Offset + Size byte. bool MachinePointerInfo::isDereferenceable(unsigned Size, LLVMContext &C, const DataLayout &DL) const { if (!V.is()) return false; const Value *BasePtr = V.get(); if (BasePtr == nullptr) return false; return isDereferenceableAndAlignedPointer( BasePtr, 1, APInt(DL.getPointerSizeInBits(), Offset + Size), DL); } /// getConstantPool - Return a MachinePointerInfo record that refers to the /// constant pool. MachinePointerInfo MachinePointerInfo::getConstantPool(MachineFunction &MF) { return MachinePointerInfo(MF.getPSVManager().getConstantPool()); } /// getFixedStack - Return a MachinePointerInfo record that refers to the /// the specified FrameIndex. MachinePointerInfo MachinePointerInfo::getFixedStack(MachineFunction &MF, int FI, int64_t Offset) { return MachinePointerInfo(MF.getPSVManager().getFixedStack(FI), Offset); } MachinePointerInfo MachinePointerInfo::getJumpTable(MachineFunction &MF) { return MachinePointerInfo(MF.getPSVManager().getJumpTable()); } MachinePointerInfo MachinePointerInfo::getGOT(MachineFunction &MF) { return MachinePointerInfo(MF.getPSVManager().getGOT()); } MachinePointerInfo MachinePointerInfo::getStack(MachineFunction &MF, int64_t Offset, uint8_t ID) { return MachinePointerInfo(MF.getPSVManager().getStack(), Offset, ID); } MachinePointerInfo MachinePointerInfo::getUnknownStack(MachineFunction &MF) { return MachinePointerInfo(MF.getDataLayout().getAllocaAddrSpace()); } MachineMemOperand::MachineMemOperand(MachinePointerInfo ptrinfo, Flags f, uint64_t s, uint64_t a, const AAMDNodes &AAInfo, const MDNode *Ranges, SyncScope::ID SSID, AtomicOrdering Ordering, AtomicOrdering FailureOrdering) : PtrInfo(ptrinfo), Size(s), FlagVals(f), BaseAlignLog2(Log2_32(a) + 1), AAInfo(AAInfo), Ranges(Ranges) { assert((PtrInfo.V.isNull() || PtrInfo.V.is() || isa(PtrInfo.V.get()->getType())) && "invalid pointer value"); assert(getBaseAlignment() == a && a != 0 && "Alignment is not a power of 2!"); assert((isLoad() || isStore()) && "Not a load/store!"); AtomicInfo.SSID = static_cast(SSID); assert(getSyncScopeID() == SSID && "Value truncated"); AtomicInfo.Ordering = static_cast(Ordering); assert(getOrdering() == Ordering && "Value truncated"); AtomicInfo.FailureOrdering = static_cast(FailureOrdering); assert(getFailureOrdering() == FailureOrdering && "Value truncated"); } /// Profile - Gather unique data for the object. /// void MachineMemOperand::Profile(FoldingSetNodeID &ID) const { ID.AddInteger(getOffset()); ID.AddInteger(Size); ID.AddPointer(getOpaqueValue()); ID.AddInteger(getFlags()); ID.AddInteger(getBaseAlignment()); } void MachineMemOperand::refineAlignment(const MachineMemOperand *MMO) { // The Value and Offset may differ due to CSE. But the flags and size // should be the same. assert(MMO->getFlags() == getFlags() && "Flags mismatch!"); assert(MMO->getSize() == getSize() && "Size mismatch!"); if (MMO->getBaseAlignment() >= getBaseAlignment()) { // Update the alignment value. BaseAlignLog2 = Log2_32(MMO->getBaseAlignment()) + 1; // Also update the base and offset, because the new alignment may // not be applicable with the old ones. PtrInfo = MMO->PtrInfo; } } /// getAlignment - Return the minimum known alignment in bytes of the /// actual memory reference. uint64_t MachineMemOperand::getAlignment() const { return MinAlign(getBaseAlignment(), getOffset()); } void MachineMemOperand::print(raw_ostream &OS) const { ModuleSlotTracker DummyMST(nullptr); print(OS, DummyMST); } void MachineMemOperand::print(raw_ostream &OS, ModuleSlotTracker &MST) const { SmallVector SSNs; LLVMContext Ctx; print(OS, MST, SSNs, Ctx, nullptr, nullptr); } void MachineMemOperand::print(raw_ostream &OS, ModuleSlotTracker &MST, SmallVectorImpl &SSNs, const LLVMContext &Context, const MachineFrameInfo *MFI, const TargetInstrInfo *TII) const { OS << '('; if (isVolatile()) OS << "volatile "; if (isNonTemporal()) OS << "non-temporal "; if (isDereferenceable()) OS << "dereferenceable "; if (isInvariant()) OS << "invariant "; if (getFlags() & MachineMemOperand::MOTargetFlag1) OS << '"' << getTargetMMOFlagName(*TII, MachineMemOperand::MOTargetFlag1) << "\" "; if (getFlags() & MachineMemOperand::MOTargetFlag2) OS << '"' << getTargetMMOFlagName(*TII, MachineMemOperand::MOTargetFlag2) << "\" "; if (getFlags() & MachineMemOperand::MOTargetFlag3) OS << '"' << getTargetMMOFlagName(*TII, MachineMemOperand::MOTargetFlag3) << "\" "; assert((isLoad() || isStore()) && "machine memory operand must be a load or store (or both)"); if (isLoad()) OS << "load "; if (isStore()) OS << "store "; printSyncScope(OS, Context, getSyncScopeID(), SSNs); if (getOrdering() != AtomicOrdering::NotAtomic) OS << toIRString(getOrdering()) << ' '; if (getFailureOrdering() != AtomicOrdering::NotAtomic) OS << toIRString(getFailureOrdering()) << ' '; if (getSize() == MemoryLocation::UnknownSize) OS << "unknown-size"; else OS << getSize(); if (const Value *Val = getValue()) { OS << ((isLoad() && isStore()) ? " on " : isLoad() ? " from " : " into "); printIRValueReference(OS, *Val, MST); } else if (const PseudoSourceValue *PVal = getPseudoValue()) { OS << ((isLoad() && isStore()) ? " on " : isLoad() ? " from " : " into "); assert(PVal && "Expected a pseudo source value"); switch (PVal->kind()) { case PseudoSourceValue::Stack: OS << "stack"; break; case PseudoSourceValue::GOT: OS << "got"; break; case PseudoSourceValue::JumpTable: OS << "jump-table"; break; case PseudoSourceValue::ConstantPool: OS << "constant-pool"; break; case PseudoSourceValue::FixedStack: { int FrameIndex = cast(PVal)->getFrameIndex(); bool IsFixed = true; printFrameIndex(OS, FrameIndex, IsFixed, MFI); break; } case PseudoSourceValue::GlobalValueCallEntry: OS << "call-entry "; cast(PVal)->getValue()->printAsOperand( OS, /*PrintType=*/false, MST); break; case PseudoSourceValue::ExternalSymbolCallEntry: OS << "call-entry &"; printLLVMNameWithoutPrefix( OS, cast(PVal)->getSymbol()); break; default: // FIXME: This is not necessarily the correct MIR serialization format for // a custom pseudo source value, but at least it allows // -print-machineinstrs to work on a target with custom pseudo source // values. OS << "custom "; PVal->printCustom(OS); break; } } MachineOperand::printOperandOffset(OS, getOffset()); if (getBaseAlignment() != getSize()) OS << ", align " << getBaseAlignment(); auto AAInfo = getAAInfo(); if (AAInfo.TBAA) { OS << ", !tbaa "; AAInfo.TBAA->printAsOperand(OS, MST); } if (AAInfo.Scope) { OS << ", !alias.scope "; AAInfo.Scope->printAsOperand(OS, MST); } if (AAInfo.NoAlias) { OS << ", !noalias "; AAInfo.NoAlias->printAsOperand(OS, MST); } if (getRanges()) { OS << ", !range "; getRanges()->printAsOperand(OS, MST); } // FIXME: Implement addrspace printing/parsing in MIR. // For now, print this even though parsing it is not available in MIR. if (unsigned AS = getAddrSpace()) OS << ", addrspace " << AS; OS << ')'; }