Index: llvm/trunk/docs/MIRLangRef.rst =================================================================== --- llvm/trunk/docs/MIRLangRef.rst +++ llvm/trunk/docs/MIRLangRef.rst @@ -191,6 +191,9 @@ tracksRegLiveness: true liveins: - { reg: '$rdi' } + callSites: + - { bb: 0, offset: 3, fwdArgRegs: + - { arg: 0, reg: '$edi' } } body: | bb.0.entry: liveins: $rdi @@ -198,6 +201,7 @@ $eax = MOV32rm $rdi, 1, _, 0, _ $eax = INC32r killed $eax, implicit-def dead $eflags MOV32mr killed $rdi, 1, _, 0, _, $eax + CALL64pcrel32 @foo RETQ $eax ... @@ -210,6 +214,9 @@ 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 ===================================== Index: llvm/trunk/include/llvm/CodeGen/MIRYamlMapping.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MIRYamlMapping.h +++ llvm/trunk/include/llvm/CodeGen/MIRYamlMapping.h @@ -347,6 +347,66 @@ 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 ArgForwardingRegs; + + bool operator==(const CallSiteInfo &Other) const { + return CallLocation.BlockNum == Other.CallLocation.BlockNum && + CallLocation.Offset == Other.CallLocation.Offset; + } +}; + +template <> struct MappingTraits { + 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 { + 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()); + } + + static const bool flow = true; +}; + struct MachineConstantPoolValue { UnsignedValue ID; StringValue Value; @@ -401,6 +461,7 @@ 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) @@ -529,6 +590,7 @@ std::vector StackObjects; std::vector Constants; /// Constant pool. std::unique_ptr MachineFuncInfo; + std::vector CallSitesInfo; MachineJumpTable JumpTableInfo; BlockStringValue Body; }; @@ -555,6 +617,8 @@ std::vector()); YamlIO.mapOptional("stack", MF.StackObjects, std::vector()); + YamlIO.mapOptional("callSites", MF.CallSitesInfo, + std::vector()); YamlIO.mapOptional("constants", MF.Constants, std::vector()); YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo); Index: llvm/trunk/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineFunction.h +++ llvm/trunk/include/llvm/CodeGen/MachineFunction.h @@ -378,9 +378,28 @@ 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; + using CallSiteInfoImpl = SmallVectorImpl; + private: Delegate *TheDelegate = nullptr; + using CallSiteInfoMap = DenseMap; + /// 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); @@ -946,6 +965,17 @@ 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; + } + }; //===--------------------------------------------------------------------===// Index: llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIRParser.cpp @@ -116,6 +116,9 @@ bool initializeFrameInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); + bool initializeCallSiteInfo(PerFunctionMIParsingState &PFS, + const yaml::MachineFunction &YamlMF); + bool parseCalleeSavedRegister(PerFunctionMIParsingState &PFS, std::vector &CSIInfo, const yaml::StringValue &RegisterSource, @@ -337,6 +340,47 @@ 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) { @@ -437,6 +481,9 @@ computeFunctionProperties(MF); + if (initializeCallSiteInfo(PFS, YamlMF)) + return false; + MF.getSubtarget().mirFileLoaded(MF); MF.verify(); Index: llvm/trunk/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRPrinter.cpp +++ llvm/trunk/lib/CodeGen/MIRPrinter.cpp @@ -129,6 +129,9 @@ 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); @@ -212,6 +215,7 @@ 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()) @@ -460,6 +464,39 @@ } } +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; Index: llvm/trunk/lib/CodeGen/MachineVerifier.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineVerifier.cpp +++ llvm/trunk/lib/CodeGen/MachineVerifier.cpp @@ -2193,6 +2193,10 @@ 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() { Index: llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error1.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error1.mir +++ llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error1.mir @@ -0,0 +1,23 @@ +# 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 + +... Index: llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error2.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error2.mir +++ llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error2.mir @@ -0,0 +1,23 @@ +# 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 + +... Index: llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error3.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error3.mir +++ llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error3.mir @@ -0,0 +1,23 @@ +# 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 + +... Index: llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error4.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error4.mir +++ llvm/trunk/test/CodeGen/MIR/X86/call-site-info-error4.mir @@ -0,0 +1,23 @@ +# 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 + +...