tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
+ callSites:
+ - { bb: 0, offset: 3, fwdArgRegs:
+ - { arg: 0, reg: '$edi' } }
body: |
bb.0.entry:
liveins: $rdi
$eax = MOV32rm $rdi, 1, _, 0, _
$eax = INC32r killed $eax, implicit-def dead $eflags
MOV32mr killed $rdi, 1, _, 0, _, $eax
+ CALL64pcrel32 @foo <regmask...>
RETQ $eax
...
The attribute ``body`` is a `YAML block literal string`_. Its value represents
the function's machine basic blocks and their machine instructions.
+The attribute ``callSites`` is a representation of call site information which
+keeps track of call instructions and registers used to transfer call arguments.
+
Machine Instructions Format Reference
=====================================
static const bool flow = true;
};
+
+/// Serializable representation of CallSiteInfo.
+struct CallSiteInfo {
+ // Representation of call argument and register which is used to
+ // transfer it.
+ struct ArgRegPair {
+ StringValue Reg;
+ uint16_t ArgNo;
+
+ bool operator==(const ArgRegPair &Other) const {
+ return Reg == Other.Reg && ArgNo == Other.ArgNo;
+ }
+ };
+
+ /// Identifies call instruction location in machine function.
+ struct MachineInstrLoc {
+ unsigned BlockNum;
+ unsigned Offset;
+
+ bool operator==(const MachineInstrLoc &Other) const {
+ return BlockNum == Other.BlockNum && Offset == Other.Offset;
+ }
+ };
+
+ MachineInstrLoc CallLocation;
+ std::vector<ArgRegPair> ArgForwardingRegs;
+
+ bool operator==(const CallSiteInfo &Other) const {
+ return CallLocation.BlockNum == Other.CallLocation.BlockNum &&
+ CallLocation.Offset == Other.CallLocation.Offset;
+ }
+};
+
+template <> struct MappingTraits<CallSiteInfo::ArgRegPair> {
+ static void mapping(IO &YamlIO, CallSiteInfo::ArgRegPair &ArgReg) {
+ YamlIO.mapRequired("arg", ArgReg.ArgNo);
+ YamlIO.mapRequired("reg", ArgReg.Reg);
+ }
+
+ static const bool flow = true;
+};
+}
+}
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<CallSiteInfo> {
+ static void mapping(IO &YamlIO, CallSiteInfo &CSInfo) {
+ YamlIO.mapRequired("bb", CSInfo.CallLocation.BlockNum);
+ YamlIO.mapRequired("offset", CSInfo.CallLocation.Offset);
+ YamlIO.mapOptional("fwdArgRegs", CSInfo.ArgForwardingRegs,
+ std::vector<CallSiteInfo::ArgRegPair>());
+ }
+
+ static const bool flow = true;
+};
+
struct MachineConstantPoolValue {
UnsignedValue ID;
StringValue Value;
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
std::vector<MachineStackObject> StackObjects;
std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
+ std::vector<CallSiteInfo> CallSitesInfo;
MachineJumpTable JumpTableInfo;
BlockStringValue Body;
};
std::vector<FixedMachineStackObject>());
YamlIO.mapOptional("stack", MF.StackObjects,
std::vector<MachineStackObject>());
+ YamlIO.mapOptional("callSites", MF.CallSitesInfo,
+ std::vector<CallSiteInfo>());
YamlIO.mapOptional("constants", MF.Constants,
std::vector<MachineConstantPoolValue>());
YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo);
virtual void MF_HandleRemoval(MachineInstr &MI) = 0;
};
+ /// Structure used to represent pair of argument number after call lowering
+ /// and register used to transfer that argument.
+ /// For now we support only cases when argument is transferred through one
+ /// register.
+ struct ArgRegPair {
+ unsigned Reg;
+ uint16_t ArgNo;
+ ArgRegPair(unsigned R, unsigned Arg) : Reg(R), ArgNo(Arg) {
+ assert(Arg < (1 << 16) && "Arg out of range");
+ }
+ };
+ /// Vector of call argument and its forwarding register.
+ using CallSiteInfo = SmallVector<ArgRegPair, 1>;
+ using CallSiteInfoImpl = SmallVectorImpl<ArgRegPair>;
+
private:
Delegate *TheDelegate = nullptr;
+ using CallSiteInfoMap = DenseMap<const MachineInstr *, CallSiteInfo>;
+ /// Map a call instruction to call site arguments forwarding info.
+ CallSiteInfoMap CallSitesInfo;
+
// Callbacks for insertion and removal.
void handleInsertion(MachineInstr &MI);
void handleRemoval(MachineInstr &MI);
const VariableDbgInfoMapTy &getVariableDbgInfo() const {
return VariableDbgInfos;
}
+
+ void addCallArgsForwardingRegs(const MachineInstr *CallI,
+ CallSiteInfoImpl &&CallInfo) {
+ assert(CallI->isCall());
+ CallSitesInfo[CallI] = std::move(CallInfo);
+ }
+
+ const CallSiteInfoMap &getCallSitesInfo() const {
+ return CallSitesInfo;
+ }
+
};
//===--------------------------------------------------------------------===//
bool initializeFrameInfo(PerFunctionMIParsingState &PFS,
const yaml::MachineFunction &YamlMF);
+ bool initializeCallSiteInfo(PerFunctionMIParsingState &PFS,
+ const yaml::MachineFunction &YamlMF);
+
bool parseCalleeSavedRegister(PerFunctionMIParsingState &PFS,
std::vector<CalleeSavedInfo> &CSIInfo,
const yaml::StringValue &RegisterSource,
Properties.set(MachineFunctionProperties::Property::NoVRegs);
}
+bool MIRParserImpl::initializeCallSiteInfo(
+ PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) {
+ MachineFunction &MF = PFS.MF;
+ SMDiagnostic Error;
+ const LLVMTargetMachine &TM = MF.getTarget();
+ for (auto YamlCSInfo : YamlMF.CallSitesInfo) {
+ yaml::CallSiteInfo::MachineInstrLoc MILoc = YamlCSInfo.CallLocation;
+ if (MILoc.BlockNum >= MF.size())
+ return error(Twine(MF.getName()) +
+ Twine(" call instruction block out of range.") +
+ " Unable to reference bb:" + Twine(MILoc.BlockNum));
+ auto CallB = std::next(MF.begin(), MILoc.BlockNum);
+ if (MILoc.Offset >= CallB->size())
+ return error(Twine(MF.getName()) +
+ Twine(" call instruction offset out of range.") +
+ "Unable to reference instruction at bb: " +
+ Twine(MILoc.BlockNum) + " at offset:" + Twine(MILoc.Offset));
+ auto CallI = std::next(CallB->begin(), MILoc.Offset);
+ if (!CallI->isCall())
+ return error(Twine(MF.getName()) +
+ Twine(" call site info should reference call "
+ "instruction. Instruction at bb:") +
+ Twine(MILoc.BlockNum) + " at offset:" + Twine(MILoc.Offset) +
+ " is not a call instruction");
+ MachineFunction::CallSiteInfo CSInfo;
+ for (auto ArgRegPair : YamlCSInfo.ArgForwardingRegs) {
+ unsigned Reg = 0;
+ if (parseNamedRegisterReference(PFS, Reg, ArgRegPair.Reg.Value, Error))
+ return error(Error, ArgRegPair.Reg.SourceRange);
+ CSInfo.emplace_back(Reg, ArgRegPair.ArgNo);
+ }
+
+ if (TM.Options.EnableDebugEntryValues)
+ MF.addCallArgsForwardingRegs(&*CallI, std::move(CSInfo));
+ }
+
+ if (YamlMF.CallSitesInfo.size() && !TM.Options.EnableDebugEntryValues)
+ return error(Twine("Call site info provided but not used"));
+ return false;
+}
+
bool
MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF,
MachineFunction &MF) {
computeFunctionProperties(MF);
+ if (initializeCallSiteInfo(PFS, YamlMF))
+ return false;
+
MF.getSubtarget().mirFileLoaded(MF);
MF.verify();
const MachineJumpTableInfo &JTI);
void convertStackObjects(yaml::MachineFunction &YMF,
const MachineFunction &MF, ModuleSlotTracker &MST);
+ void convertCallSiteObjects(yaml::MachineFunction &YMF,
+ const MachineFunction &MF,
+ ModuleSlotTracker &MST);
private:
void initRegisterMaskIds(const MachineFunction &MF);
MST.incorporateFunction(MF.getFunction());
convert(MST, YamlMF.FrameInfo, MF.getFrameInfo());
convertStackObjects(YamlMF, MF, MST);
+ convertCallSiteObjects(YamlMF, MF, MST);
if (const auto *ConstantPool = MF.getConstantPool())
convert(YamlMF, *ConstantPool);
if (const auto *JumpTableInfo = MF.getJumpTableInfo())
}
}
+void MIRPrinter::convertCallSiteObjects(yaml::MachineFunction &YMF,
+ const MachineFunction &MF,
+ ModuleSlotTracker &MST) {
+ const auto *TRI = MF.getSubtarget().getRegisterInfo();
+ for (auto CSInfo : MF.getCallSitesInfo()) {
+ yaml::CallSiteInfo YmlCS;
+ yaml::CallSiteInfo::MachineInstrLoc CallLocation;
+
+ // Prepare instruction position.
+ MachineBasicBlock::const_iterator CallI = CSInfo.first->getIterator();
+ CallLocation.BlockNum = CallI->getParent()->getNumber();
+ // Get call instruction offset from the beginning of block.
+ CallLocation.Offset = std::distance(CallI->getParent()->begin(), CallI);
+ YmlCS.CallLocation = CallLocation;
+ // Construct call arguments and theirs forwarding register info.
+ for (auto ArgReg : CSInfo.second) {
+ yaml::CallSiteInfo::ArgRegPair YmlArgReg;
+ YmlArgReg.ArgNo = ArgReg.ArgNo;
+ printRegMIR(ArgReg.Reg, YmlArgReg.Reg, TRI);
+ YmlCS.ArgForwardingRegs.emplace_back(YmlArgReg);
+ }
+ YMF.CallSitesInfo.push_back(YmlCS);
+ }
+
+ // Sort call info by position of call instructions.
+ llvm::sort(YMF.CallSitesInfo.begin(), YMF.CallSitesInfo.end(),
+ [](yaml::CallSiteInfo A, yaml::CallSiteInfo B) {
+ if (A.CallLocation.BlockNum == B.CallLocation.BlockNum)
+ return A.CallLocation.Offset < B.CallLocation.Offset;
+ return A.CallLocation.BlockNum < B.CallLocation.BlockNum;
+ });
+}
+
void MIRPrinter::convert(yaml::MachineFunction &MF,
const MachineConstantPool &ConstantPool) {
unsigned ID = 0;
verifyLiveVariables();
if (LiveInts)
verifyLiveIntervals();
+
+ for (auto CSInfo : MF->getCallSitesInfo())
+ if (!CSInfo.first->isCall())
+ report("Call site info referencing instruction that is not call", MF);
}
void MachineVerifier::verifyLiveVariables() {
--- /dev/null
+# RUN: not llc -mtriple=x86_64-- -run-pass none -debug-entry-values %s -o - 2>&1 | FileCheck %s
+# CHECK: baa call instruction block out of range. Unable to reference bb:1
+--- |
+ define dso_local i32 @baa(i32 %a) local_unnamed_addr {
+ entry:
+ %call = tail call i32 @foo(i32 %a)
+ ret i32 %call
+ }
+
+ declare dso_local i32 @foo(i32) local_unnamed_addr
+...
+---
+name: baa
+callSites:
+ - {bb: 1, offset: 0, fwdArgRegs:
+ - { arg: 0, reg: '$edi' } }
+body: |
+ bb.0:
+ liveins: $edi
+
+ TAILJMPd64 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $edi
+
+...
--- /dev/null
+# RUN: not llc -mtriple=x86_64-- -run-pass none -debug-entry-values %s -o - 2>&1 | FileCheck %s
+# CHECK: baa call instruction offset out of range.Unable to reference instruction at bb: 0 at offset:1
+--- |
+ define dso_local i32 @baa(i32 %a) local_unnamed_addr {
+ entry:
+ %call = tail call i32 @foo(i32 %a)
+ ret i32 %call
+ }
+
+ declare dso_local i32 @foo(i32) local_unnamed_addr
+...
+---
+name: baa
+callSites:
+ - {bb: 0, offset: 1, fwdArgRegs:
+ - { arg: 0, reg: '$edi' } }
+body: |
+ bb.0:
+ liveins: $edi
+
+ TAILJMPd64 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $edi
+
+...
--- /dev/null
+# RUN: not llc -mtriple=x86_64-- -run-pass none -debug-entry-values %s -o - 2>&1 | FileCheck %s
+# CHECK: baa call site info should reference call instruction. Instruction at bb:0 at offset:0 is not a call instruction
+--- |
+ define dso_local i32 @baa(i32 %a) local_unnamed_addr {
+ entry:
+ %call = tail call i32 @foo(i32 %a)
+ ret i32 %call
+ }
+
+ declare dso_local i32 @foo(i32) local_unnamed_addr
+...
+---
+name: baa
+callSites:
+ - {bb: 0, offset: 0, fwdArgRegs:
+ - { arg: 0, reg: '$edi' } }
+body: |
+ bb.0:
+ liveins: $edi
+ renamable $edi = nsw ADD32ri8 killed renamable $edi, 4, implicit-def dead $eflags
+ TAILJMPd64 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $edi
+
+...
--- /dev/null
+# RUN: not llc -mtriple=x86_64-- -run-pass none %s -o - 2>&1 | FileCheck %s
+# CHECK: Call site info provided but not used
+--- |
+ define dso_local i32 @baa(i32 %a) local_unnamed_addr {
+ entry:
+ %call = tail call i32 @foo(i32 %a)
+ ret i32 %call
+ }
+
+ declare dso_local i32 @foo(i32) local_unnamed_addr
+...
+---
+name: baa
+callSites:
+ - {bb: 0, offset: 0, fwdArgRegs:
+ - { arg: 0, reg: '$edi' } }
+body: |
+ bb.0:
+ liveins: $edi
+
+ TAILJMPd64 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $edi
+
+...