Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -389,6 +389,14 @@ /// this DBG_VALUE instruction. const DIExpression *getDebugExpression() const; + /// Return the call site referenced by + /// this DBG_CALLSITE instruction. + const DICallSite *getDebugCallSite() const; + + /// Return the call site parameter refrenced + /// by this DBG_CALL_SITEPARAM instruction + const DICallSiteParam *getDebugCallSiteParam() const; + /// Return the debug label referenced by /// this DBG_LABEL instruction. const DILabel *getDebugLabel() const; @@ -995,7 +1003,16 @@ bool isDebugValue() const { return getOpcode() == TargetOpcode::DBG_VALUE; } bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; } - bool isDebugInstr() const { return isDebugValue() || isDebugLabel(); } + bool isDebugCallSite() const { + return getOpcode() == TargetOpcode::DBG_CALLSITE; + } + bool isDebugCallSiteParam() const { + return getOpcode() == TargetOpcode::DBG_CALLSITEPARAM; + } + bool isDebugInstr() const { + return isDebugValue() || isDebugLabel() || isDebugCallSite() || + isDebugCallSiteParam(); + } /// A DBG_VALUE is indirect iff the first operand is a register and /// the second operand is an immediate. @@ -1075,6 +1092,8 @@ case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: case TargetOpcode::DBG_VALUE: + case TargetOpcode::DBG_CALLSITE: + case TargetOpcode::DBG_CALLSITEPARAM: case TargetOpcode::DBG_LABEL: case TargetOpcode::LIFETIME_START: case TargetOpcode::LIFETIME_END: Index: include/llvm/CodeGen/SelectionDAG.h =================================================================== --- include/llvm/CodeGen/SelectionDAG.h +++ include/llvm/CodeGen/SelectionDAG.h @@ -72,6 +72,8 @@ class MCSymbol; class OptimizationRemarkEmitter; class SDDbgValue; +class SDDbgCallSite; +class SDDbgCallSiteParam; class SDDbgLabel; class SelectionDAG; class SelectionDAGTargetInfo; @@ -147,7 +149,12 @@ class SDDbgInfo { BumpPtrAllocator Alloc; SmallVector DbgValues; - SmallVector ByvalParmDbgValues; + using DbgCallMap = DenseMap>; + DbgCallMap DbgCallSites; + using DbgCallParamMap = + DenseMap>; + DbgCallParamMap DbgCallParams; + SmallVector ByvalParmDbgValues; SmallVector DbgLabels; using DbgValMapType = DenseMap>; DbgValMapType DbgValMap; @@ -169,6 +176,14 @@ DbgLabels.push_back(L); } + void add(SDDbgCallSite *CS, const SDNode *Node) { + DbgCallSites[Node].push_back(CS); + } + + void add(SDDbgCallSiteParam *CSP, const SDNode *Node) { + DbgCallParams[Node].push_back(CSP); + } + /// Invalidate all DbgValues attached to the node and remove /// it from the Node-to-DbgValues map. void erase(const SDNode *Node); @@ -176,6 +191,8 @@ void clear() { DbgValMap.clear(); DbgValues.clear(); + DbgCallSites.clear(); + DbgCallParams.clear(); ByvalParmDbgValues.clear(); DbgLabels.clear(); Alloc.Reset(); @@ -184,7 +201,8 @@ BumpPtrAllocator &getAlloc() { return Alloc; } bool empty() const { - return DbgValues.empty() && ByvalParmDbgValues.empty() && DbgLabels.empty(); + return DbgValues.empty() && ByvalParmDbgValues.empty() && + DbgCallSites.empty() && DbgCallParams.empty() && DbgLabels.empty(); } ArrayRef getSDDbgValues(const SDNode *Node) const { @@ -194,6 +212,20 @@ return ArrayRef(); } + ArrayRef getSDDbgCallSites(const SDNode *Node) { + DbgCallMap::iterator I = DbgCallSites.find(Node); + if (I != DbgCallSites.end()) + return I->second; + return ArrayRef(); + } + + ArrayRef getSDDbgCallParam(const SDNode *Node) { + DbgCallParamMap::iterator I = DbgCallParams.find(Node); + if (I != DbgCallParams.end()) + return I->second; + return nullptr; + } + using DbgIterator = SmallVectorImpl::iterator; using DbgLabelIterator = SmallVectorImpl::iterator; @@ -264,7 +296,7 @@ /// Pool allocation for misc. objects that are created once per SelectionDAG. BumpPtrAllocator Allocator; - /// Tracks dbg_value and dbg_label information through SDISel. + /// Tracks dbg_value, dbg_label and dbg_callsite information through SDISel. SDDbgInfo *DbgInfo; uint16_t NextPersistentId = 0; @@ -1274,6 +1306,24 @@ void transferDbgValues(SDValue From, SDValue To, unsigned OffsetInBits = 0, unsigned SizeInBits = 0, bool InvalidateDbg = true); + /// Creates a SDDbgCallSite node. + SDDbgCallSite *getDbgCallSite(DICallSite *CS, uint64_t isTailCall, + uint64_t regCS, const DebugLoc &DL, unsigned O); + + /// Creates a SDDbgCallSiteParam from SDNode. + SDDbgCallSiteParam *getDbgCallSiteParam(MDNode *CSP, SDNode *N, unsigned Res, + uint64_t Reg, unsigned O, + SDDbgCallSite *SDC); + + /// Creates a SDDbgCallSiteParam from frame index. + SDDbgCallSiteParam *getDbgCallSiteFrameParam(MDNode *CSP, unsigned FI, + uint64_t Reg, unsigned O, + SDDbgCallSite *SDC); + + /// Creates a SDDbgCallSiteParam from constant. + SDDbgCallSiteParam *getConstantDbgCallParam(MDNode *CSP, const Value *C, + uint64_t Reg, unsigned O, SDDbgCallSite *SDC); + /// Remove the specified node from the system. If any of its /// operands then becomes dead, remove them as well. Inform UpdateListener /// for each node deleted. @@ -1352,11 +1402,27 @@ /// Add a dbg_label SDNode. void AddDbgLabel(SDDbgLabel *DB); + /// Add a dbg_callsite SDNode. + void AddDbgCallSite(SDDbgCallSite *CS, const SDNode *SD); + + /// Add a dbg_callsiteparam SDNode. + void AddDbgCallParam(SDDbgCallSite *CS, SDDbgCallSiteParam *CSP, SDNode *SD); + /// Get the debug values which reference the given SDNode. ArrayRef GetDbgValues(const SDNode* SD) const { return DbgInfo->getSDDbgValues(SD); } + /// Get the debug call sites which reference the given SDNode. + ArrayRef GetDbgCallSites(const SDNode* SD) { + return DbgInfo->getSDDbgCallSites(SD); + } + + /// Get the debug site params which reference the given SDNode. + ArrayRef GetDbgCallParam(const SDNode *SD) { + return DbgInfo->getSDDbgCallParam(SD); + } + public: /// Return true if there are any SDDbgValue nodes associated /// with this SelectionDAG. Index: include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- include/llvm/CodeGen/SelectionDAGNodes.h +++ include/llvm/CodeGen/SelectionDAGNodes.h @@ -495,10 +495,11 @@ friend class SelectionDAG; uint16_t HasDebugValue : 1; + uint16_t HasDebugCallParam : 1; uint16_t IsMemIntrinsic : 1; uint16_t IsDivergent : 1; }; - enum { NumSDNodeBits = 3 }; + enum { NumSDNodeBits = 4 }; class ConstantSDNodeBitfields { friend class ConstantSDNode; @@ -696,6 +697,9 @@ bool getHasDebugValue() const { return SDNodeBits.HasDebugValue; } void setHasDebugValue(bool b) { SDNodeBits.HasDebugValue = b; } + bool getHasDebugCallParam() const { return SDNodeBits.HasDebugCallParam; } + void setHasDebugCallParam(bool b) { SDNodeBits.HasDebugCallParam = b; } + bool isDivergent() const { return SDNodeBits.IsDivergent; } /// Return true if there are no uses of this node. @@ -1290,6 +1294,7 @@ }; memcpy(&RawSDNodeBits, &this->RawSDNodeBits, sizeof(this->RawSDNodeBits)); SDNodeBits.HasDebugValue = 0; + SDNodeBits.HasDebugCallParam = 0; SDNodeBits.IsDivergent = false; memcpy(&Data, &RawSDNodeBits, sizeof(RawSDNodeBits)); return Data; Index: include/llvm/CodeGen/TargetLowering.h =================================================================== --- include/llvm/CodeGen/TargetLowering.h +++ include/llvm/CodeGen/TargetLowering.h @@ -3408,6 +3408,18 @@ return false; } + /// Some architectures like i686, PPC, SPARC, Mips, Lanai use global base reg + /// as part of function call sequence when they are compiled in PIC mode to + /// hold the address of the global offset table. + /// FIXME: Some target lowering backends reserve special enum for marking + /// such node in first part of SelectionDAG. Other may reserve virtual + /// register in first phase. But at the end of instruction selection + /// process this register will be known and it can be obtained from + /// corresponding MachingFunctionInfo class. This interface should + /// be extended with proper MachineFunction in order to perform + /// such check. + virtual bool isGlobalBaseReg(SDNode *) const { return false; } + /// Return true if the target may be able emit the call instruction as a tail /// call. This is used by optimization passes to determine if it's profitable /// to duplicate return instructions to enable tailcall optimization. Index: include/llvm/CodeGen/TargetRegisterInfo.h =================================================================== --- include/llvm/CodeGen/TargetRegisterInfo.h +++ include/llvm/CodeGen/TargetRegisterInfo.h @@ -1002,6 +1002,16 @@ } }; + +class CalleeSavedRegChecker { + const uint32_t *CallSavedRegs; +public: + CalleeSavedRegChecker(const MachineFunction *MF); + bool isCalleeSaved(unsigned Reg) { + return (CallSavedRegs[Reg / 32] >> Reg % 32) & 1; + } +}; + //===----------------------------------------------------------------------===// // SuperRegClassIterator //===----------------------------------------------------------------------===// Index: include/llvm/Support/TargetOpcodes.def =================================================================== --- include/llvm/Support/TargetOpcodes.def +++ include/llvm/Support/TargetOpcodes.def @@ -77,6 +77,14 @@ /// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic HANDLE_TARGET_OPCODE(DBG_VALUE) +/// DBG_CALLSITE - a mapping of the !CallSite metadata node +HANDLE_TARGET_OPCODE(DBG_CALLSITE) + +/// DBG_CALLSITEPARAM - Holds parameters transferring locations, +/// DICallSiteParam and parameter's location that is still valid +/// and the same as it was at function call point. +HANDLE_TARGET_OPCODE(DBG_CALLSITEPARAM) + /// DBG_LABEL - a mapping of the llvm.dbg.label intrinsic HANDLE_TARGET_OPCODE(DBG_LABEL) Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -1020,6 +1020,21 @@ let AsmString = "DBG_VALUE"; let hasSideEffects = 0; } + +def DBG_CALLSITE : StandardPseudoInstruction { + let OutOperandList = (outs); + let InOperandList = (ins variable_ops); + let AsmString = "DBG_CALLSITE"; + let hasSideEffects = 0; +} + +def DBG_CALLSITEPARAM: StandardPseudoInstruction { + let OutOperandList = (outs); + let InOperandList = (ins variable_ops); + let AsmString = "DBG_CALLSITEPARAM"; + let hasSideEffects = 0; +} + def DBG_LABEL : StandardPseudoInstruction { let OutOperandList = (outs); let InOperandList = (ins unknown:$label); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -795,6 +795,26 @@ AP.OutStreamer->AddBlankLine(); } +static void printExpression(const DIExpression *Expr, + raw_svector_ostream &OS, + AsmPrinter &AP) { + if (Expr->getNumElements()) { + OS << '['; + bool NeedSep = false; + for (auto Op : Expr->expr_ops()) { + if (NeedSep) + OS << ", "; + else + NeedSep = true; + + OS << dwarf::OperationEncodingString(Op.getOp()); + for (unsigned I = 0; I < Op.getNumArgs(); ++I) + OS << ' ' << Op.getArg(I); + } + OS << "] "; + } +} + /// emitDebugValueComment - This method handles the target-independent form /// of DBG_VALUE, returning true if it was able to do so. A false return /// means the target will need to handle MI in EmitInstruction. @@ -819,21 +839,7 @@ // The second operand is only an offset if it's an immediate. bool MemLoc = MI->getOperand(0).isReg() && MI->getOperand(1).isImm(); int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0; - const DIExpression *Expr = MI->getDebugExpression(); - if (Expr->getNumElements()) { - OS << '['; - bool NeedSep = false; - for (auto Op : Expr->expr_ops()) { - if (NeedSep) - OS << ", "; - else - NeedSep = true; - OS << dwarf::OperationEncodingString(Op.getOp()); - for (unsigned I = 0; I < Op.getNumArgs(); ++I) - OS << ' ' << Op.getArg(I); - } - OS << "] "; - } + printExpression(MI->getDebugExpression(), OS, AP); // Register or immediate value. Register 0 means undef. if (MI->getOperand(0).isFPImm()) { @@ -885,6 +891,100 @@ return true; } +static bool emitDebugCallSiteComment(const MachineInstr *MI, AsmPrinter &AP) { + if (MI->getNumOperands() != 3) + return false; + + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << "DEBUG_CALLSITE: "; + + const DICallSite *V = MI->getDebugCallSite(); + if (auto *SP = dyn_cast(V->getScope())) { + StringRef Name = SP->getName(); + if (!Name.empty()) + OS << Name << ":"; + } + + int64_t isTailCall = MI->getOperand(0).getImm(); + OS << " isTailCall: " << isTailCall; + + uint64_t regCS = MI->getOperand(1).getReg(); + if (regCS == 0) + OS << ", register: %noreg" << regCS; + else + OS << ", register: " << regCS; + + // NOTE: Want this comment at start of line, don't emit with AddComment. + AP.OutStreamer->emitRawComment(OS.str()); + return true; +} + +static bool emitDebugCallSiteParamComment(const MachineInstr *MI, + AsmPrinter &AP) { + if (MI->getNumOperands() != 4 && MI->getNumOperands() != 5) + return false; + + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << " DBG_PARAM: "; + + const DICallSiteParam *CSP = MI->getDebugCallSiteParam(); + const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); + OS << " arg" << CSP->getArgNo() << ":"; + OS << " " << printReg(MI->getOperand(0).getReg(), TRI) << " <- "; + + MachineOperand Op2 = MI->getOperand(2); + DILocalVariable *Var = CSP->getVar(); + bool MemLoc = MI->getOperand(2).isReg() && MI->getOperand(3).isImm(); + int64_t Offset = MemLoc ? MI->getOperand(3).getImm() : 0; + + if (Op2.isReg() && Op2.getReg()) { + if (Op2.getReg() != MI->getOperand(0).getReg()) { + OS << printReg(Op2.getReg(), TRI); + if (MI->getNumOperands() == 5 && MI->getOperand(4).isMetadata()) + printExpression(cast(MI->getOperand(4).getMetadata()), OS, + AP); + if (MemLoc && Offset) + OS << " + " << Offset; + } else { // Print location from first two operands + if (Var) + OS << Var->getName() << " "; + printExpression(CSP->getExpression(), OS, AP); + } + } else if (Op2.isFI()) { + unsigned Reg; + const TargetFrameLowering *TFI = AP.MF->getSubtarget().getFrameLowering(); + Offset += TFI->getFrameIndexReference(*AP.MF, Op2.getIndex(), Reg); + OS << printReg(Reg, TRI); + if (Offset) + OS << " + " << Offset; + } else { // This is constant location from operand 2 + if (MI->getOperand(2).isFPImm()) { + APFloat APF = APFloat(MI->getOperand(2).getFPImm()->getValueAPF()); + if (MI->getOperand(2).getFPImm()->getType()->isFloatTy()) { + OS << (double)APF.convertToFloat(); + } else if (MI->getOperand(2).getFPImm()->getType()->isDoubleTy()) { + OS << APF.convertToDouble(); + } else { + // There is no good way to print long double. Convert a copy to + // double. Ah well, it's only a comment. + bool ignored; + APF.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, + &ignored); + OS << "(long double) " << APF.convertToDouble(); + } + } else if (MI->getOperand(2).isImm()) { + OS << MI->getOperand(2).getImm(); + } else if (MI->getOperand(2).isCImm()) { + MI->getOperand(2).getCImm()->getValue().print(OS, false /*isSigned*/); + } + } + + AP.OutStreamer->emitRawComment(OS.str()); + return true; +} + /// This method handles the target-independent form of DBG_LABEL, returning /// true if it was able to do so. A false return means the target will need /// to handle MI in EmitInstruction. @@ -1076,6 +1176,23 @@ EmitInstruction(&MI); } break; + case TargetOpcode::DBG_CALLSITE: + if (isVerbose()) { + if (!emitDebugCallSiteComment(&MI, *this)) + EmitInstruction(&MI); + auto It = MI.getIterator(); + while (It->isBundledWithSucc()) { + It++; + if (!emitDebugCallSiteParamComment(&*It, *this)) + EmitInstruction(&*It); + } + } + break; + case TargetOpcode::DBG_CALLSITEPARAM: + if (isVerbose()) + if (!emitDebugCallSiteParamComment(&MI, *this)) + EmitInstruction(&MI); + break; case TargetOpcode::DBG_LABEL: if (isVerbose()) { if (!emitDebugLabelComment(&MI, *this)) Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -809,14 +809,28 @@ return cast(getOperand(0).getMetadata()); } +const DICallSite *MachineInstr::getDebugCallSite() const { + assert(isDebugCallSite() && "not a DBG_CALLSITE"); + return cast(getOperand(2).getMetadata()); +} + +const DICallSiteParam *MachineInstr::getDebugCallSiteParam() const { + assert(isDebugCallSiteParam() && "not a DBG_CALLSITEPARAM"); + return cast(getOperand(1).getMetadata()); +} + const DILocalVariable *MachineInstr::getDebugVariable() const { assert(isDebugValue() && "not a DBG_VALUE"); return cast(getOperand(2).getMetadata()); } const DIExpression *MachineInstr::getDebugExpression() const { - assert(isDebugValue() && "not a DBG_VALUE"); - return cast(getOperand(3).getMetadata()); + assert((isDebugValue() || isDebugCallSiteParam()) && + "not a DBG_VALUE nor DBG_CALLSITEPARAM"); + if (isDebugValue()) + return cast(getOperand(3).getMetadata()); + else + return getDebugCallSiteParam()->getExpression(); } const TargetRegisterClass* @@ -1592,6 +1606,26 @@ MO.print(OS, MST, TypeToPrint, /*PrintDef=*/true, IsStandalone, ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo); } + } else if (isDebugCallSite() && MO.isMetadata()) { + // Pretty print DBG_CALLSITE instructions. + LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{}; + unsigned TiedOperandIdx = getTiedOperandIdx(i); + MO.print(OS, MST, TypeToPrint, /*PrintDef=*/true, IsStandalone, + ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo); + } else if (isDebugCallSiteParam() && MO.isMetadata()) { + // Pretty print DBG_CALLSITEPARAM instructions. + if (auto *DISCP = dyn_cast(MO.getMetadata())) { + DILocalVariable *DILV = DISCP->getVar(); + if (DILV) + OS << "\"" << DILV->getName().str() << '\"'; + if (DISCP->getExpression()->getNumElements()) + OS << " " << *DISCP->getExpression() << " "; + } else { + LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{}; + unsigned TiedOperandIdx = getTiedOperandIdx(i); + MO.print(OS, MST, TypeToPrint, /*PrintDef=*/true, IsStandalone, + ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo); + } } else if (isDebugLabel() && MO.isMetadata()) { // Pretty print DBG_LABEL instructions. auto *DIL = dyn_cast(MO.getMetadata()); Index: lib/CodeGen/PatchableFunction.cpp =================================================================== --- lib/CodeGen/PatchableFunction.cpp +++ lib/CodeGen/PatchableFunction.cpp @@ -48,6 +48,8 @@ case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: case TargetOpcode::DBG_VALUE: + case TargetOpcode::DBG_CALLSITE: + case TargetOpcode::DBG_CALLSITEPARAM: case TargetOpcode::DBG_LABEL: return true; } Index: lib/CodeGen/SelectionDAG/InstrEmitter.h =================================================================== --- lib/CodeGen/SelectionDAG/InstrEmitter.h +++ lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -112,6 +112,14 @@ MachineInstr *EmitDbgValue(SDDbgValue *SD, DenseMap &VRBaseMap); + /// Generate machine instruction for a dbg_callsite node. + MachineInstr *EmitDbgCallSite(SDDbgCallSite *SD, + DenseMap &VRBaseMap); + + /// Generate machine instruction for a dbg_callsiteparam node. + MachineInstr *EmitDbgCallSiteParam(SDDbgCallSiteParam *SD, const DebugLoc DL, + DenseMap &VRBaseMap); + /// Generate machine instruction for a dbg_label node. MachineInstr *EmitDbgLabel(SDDbgLabel *SD); Index: lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -779,6 +779,90 @@ return &*MIB; } +MachineInstr * +InstrEmitter::EmitDbgCallSite(SDDbgCallSite *SD, + DenseMap &VRBaseMap) { + MachineBasicBlock *BB = getBlock(); + MachineBasicBlock::iterator InsertPos = + SD->isSpecialCallSite() ? getInsertPos() : std::prev(getInsertPos()); + MDNode *CS = SD->getCallSite(); + DebugLoc DL = SD->getDebugLoc(); + uint64_t isTail = SD->getIsTail(); + uint64_t regCS = SD->getRegCS(); + + assert(cast(CS)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + MachineInstrBuilder MIB; + const MCInstrDesc &II = TII->get(TargetOpcode::DBG_CALLSITE); + + MIB = BuildMI(*BB, InsertPos, DL, II); + MIB.addImm(isTail); + MIB.addReg(regCS, RegState::Debug); + MIB.addMetadata(CS); + + for (auto Params : SD->getParams()) { + if (Params->isInvalidated()) + continue; + MachineInstr *CSParam = EmitDbgCallSiteParam(Params, DL, VRBaseMap); + MIBundleBuilder(&*MIB).append(CSParam); + Params->setIsInvalidated(); + } + + return &*MIB; +} + +MachineInstr * +InstrEmitter::EmitDbgCallSiteParam(SDDbgCallSiteParam *SD, const DebugLoc DL, + DenseMap &VRBaseMap) { + MDNode *CSP = SD->getCallSiteParam(); + assert(cast(CSP) && "This needs to be callsiteparam"); + + const MCInstrDesc &II = TII->get(TargetOpcode::DBG_CALLSITEPARAM); + MachineInstrBuilder MIB = BuildMI(*MF, DL, II); + MIB.addReg(SD->getReg(), getDebugRegState(true)); + MIB.addMetadata(CSP); + + if (SD->getKind() == SDDbgCallSiteParam::FRAMEIX) { + // Stack address; this needs to be lowered in target-dependent fashion. + // EmitTargetCodeForFrameDebugValue is responsible for allocation. + MIB.addFrameIndex(SD->getFrameIx()); + MIB.addImm(/*Offset*/ 0); + return &*MIB; + } else if (SD->getKind() == SDDbgCallSiteParam::SDNODE) { + SDNode *Node = SD->getSDNode(); + SDValue Op = SDValue(Node, SD->getResNo()); + // It's possible we replaced this SDNode with other(s) and therefore + // didn't generate code for it. It's better to catch these cases where + // they happen and transfer the debug info, but trying to guarantee that + // in all cases would be very fragile; this is a safeguard for any + // that were missed. + DenseMap::iterator I = VRBaseMap.find(Op); + if (I == VRBaseMap.end()) + MIB.addReg(0U); // undef + else + AddOperand(MIB, Op, (*MIB).getNumOperands(), &II, VRBaseMap, + /*IsDebug=*/true, /*IsClone=*/false, /*IsCloned=*/false); + } else if (SD->getKind() == SDDbgCallSiteParam::CONST) { + const Value *V = SD->getConst(); + if (const ConstantInt *CI = dyn_cast(V)) { + if (CI->getBitWidth() > 64) + MIB.addCImm(CI); + else + MIB.addImm(CI->getSExtValue()); + } else if (const ConstantFP *CF = dyn_cast(V)) { + MIB.addFPImm(CF); + } else { + // Could be an Undef. In any case insert an Undef so we can see what we + // dropped. + MIB.addReg(0U); + } + } + + MIB.addReg(0U, RegState::Debug); + + return &*MIB; +} + MachineInstr * InstrEmitter::EmitDbgLabel(SDDbgLabel *SD) { MDNode *Label = SD->getLabel(); Index: lib/CodeGen/SelectionDAG/SDNodeDbgValue.h =================================================================== --- lib/CodeGen/SelectionDAG/SDNodeDbgValue.h +++ lib/CodeGen/SelectionDAG/SDNodeDbgValue.h @@ -139,6 +139,139 @@ LLVM_DUMP_METHOD void print(raw_ostream &OS) const; }; +class SDDbgCallSiteParam { +public: + enum DbgParamKind { + SDNODE = 0, // value is the result of an expression + CONST = 1, + FRAMEIX = 2 // value is contents of a stack location + }; + +private: + union { + struct { + SDNode *Node; // valid for expressions + unsigned ResNo; // valid for expressions + } s; + const Value *Const; // valid for constants + unsigned FrameIx; // valid for stack objects + } u; + MDNode *CSP; + uint64_t PhysReg; + unsigned Order; + enum DbgParamKind kind; + bool Invalid = false; + SDDbgCallSite *Parent; + +public: + // Constructor for non-constants. + SDDbgCallSiteParam(MDNode *CSP, SDNode *N, unsigned R, uint64_t reg, + unsigned O, SDDbgCallSite *SDC) + : CSP(CSP), PhysReg(reg), Order(O), Parent(SDC) { + kind = SDNODE; + u.s.Node = N; + u.s.ResNo = R; + } + + // Constructor for constants. + SDDbgCallSiteParam(MDNode *CSP, const Value *C, uint64_t Reg, unsigned O, + SDDbgCallSite *SDC) + : CSP(CSP), PhysReg(Reg), Order(O), Parent(SDC) { + kind = CONST; + u.Const = C; + } + + // Constructor for frame indices. + SDDbgCallSiteParam(MDNode *CSP, unsigned FI, uint64_t Reg, unsigned O, + SDDbgCallSite *SDC) + : CSP(CSP), PhysReg(Reg), Order(O), Parent(SDC) { + kind = FRAMEIX; + u.FrameIx = FI; + } + + void setParent(SDDbgCallSite *SDCS) { Parent = SDCS; } + SDDbgCallSite *getParent() { return Parent; } + + // Returns the kind. + DbgParamKind getKind() const { return kind; } + + // Returns the MDNode pointer for the variable. + MDNode *getCallSiteParam() const { return CSP; } + + // Returns the SDNode* for a register ref + SDNode *getSDNode() const { + assert(kind == SDNODE); + return u.s.Node; + } + + // Returns the ResNo for a register ref + unsigned getResNo() const { + assert(kind == SDNODE); + return u.s.ResNo; + } + + // Returns the FrameIx for a stack object + unsigned getFrameIx() const { + assert(kind == FRAMEIX); + return u.FrameIx; + } + + // Returns the Value* for a constant + const Value *getConst() const { + assert(kind == CONST); + return u.Const; + } + + uint64_t getReg() const { return PhysReg; } + + // Returns the SDNodeOrder. This is the order of the preceding node in the + // input. + unsigned getOrder() const { return Order; } + + // setIsInvalidated / isInvalidated - Setter / getter of the "Invalidated" + // property. A SDDbgParam is invalid if the SDNode that produces the value is + // deleted. + void setIsInvalidated() { Invalid = true; } + bool isInvalidated() const { return Invalid; } +}; + +class SDDbgCallSite { + MDNode *CS; + uint64_t isTailCall; + uint64_t regCS; + DebugLoc DL; + SmallVector Params; + unsigned Order; + bool Invalid = false; + bool specialCallSite = false; + +public: + SDDbgCallSite(MDNode *CS, uint64_t isTailCall, uint64_t regCS, DebugLoc dl, + unsigned O) + : CS(CS), isTailCall(isTailCall), regCS(regCS), DL(std::move(dl)), + Order(O) {} + + /// Returns the MDNode pointer for the callsite. + MDNode *getCallSite() const { return CS; } + + /// Return call site parameters. + SmallVector getParams() { return Params; } + + /// Add call site parameter. + void addCallSiteParam(SDDbgCallSiteParam *SDCSP) { Params.push_back(SDCSP); } + + /// Returns the DebugLoc. + DebugLoc getDebugLoc() const { return DL; } + unsigned getOrder() const { return Order; } + uint64_t getIsTail() const { return isTailCall; } + uint64_t getRegCS() const { return regCS; } + + void setIsSpecialCallSite() { specialCallSite = true; } + bool isSpecialCallSite() { return specialCallSite; } + void setIsInvalidated() { Invalid = true; } + bool isInvalidated() const { return Invalid; } +}; + /// Holds the information from a dbg_label node through SDISel. /// We do not use SDValue here to avoid including its header. class SDDbgLabel { Index: lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -734,6 +734,21 @@ } } +static void +ProcessSDDbgCallSite(SDNode *N, SelectionDAG *DAG, InstrEmitter &Emitter, + SmallVectorImpl > &Orders, + DenseMap &VRBaseMap, + unsigned Order) { + // Opportunistically insert immediate dbg_value uses, i.e. those with source + // order number right after the N. + ArrayRef DCSs = DAG->GetDbgCallSites(N); + for (unsigned i = 0, e = DCSs.size(); i != e; ++i) { + unsigned DCSOrder = DCSs[i]->getOrder(); + if (!Order || DCSOrder == ++Order) + Emitter.EmitDbgCallSite(DCSs[i], VRBaseMap); + } +} + // ProcessSourceNode - Process nodes with source order numbers. These are added // to a vector which EmitSchedule uses to determine how to insert dbg_value // instructions in the right order. @@ -747,6 +762,7 @@ // Process any valid SDDbgValues even if node does not have any order // assigned. ProcessSDDbgValues(N, DAG, Emitter, Orders, VRBaseMap, 0); + ProcessSDDbgCallSite(N, DAG, Emitter, Orders, VRBaseMap, 0); return; } @@ -762,6 +778,7 @@ // Even if no instruction was generated, a Value may have become defined via // earlier nodes. Try to process them now. ProcessSDDbgValues(N, DAG, Emitter, Orders, VRBaseMap, Order); + ProcessSDDbgCallSite(N, DAG, Emitter, Orders, VRBaseMap, Order); } void ScheduleDAGSDNodes:: Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -758,11 +758,25 @@ void SDDbgInfo::erase(const SDNode *Node) { DbgValMapType::iterator I = DbgValMap.find(Node); - if (I == DbgValMap.end()) - return; - for (auto &Val: I->second) - Val->setIsInvalidated(); - DbgValMap.erase(I); + if (I != DbgValMap.end()) { + for (auto &Val : I->second) + Val->setIsInvalidated(); + DbgValMap.erase(I); + } + + DbgCallParamMap::iterator Icsp = DbgCallParams.find(Node); + if (Icsp != DbgCallParams.end()) { + for (auto &Val : Icsp->second) + Val->setIsInvalidated(); + DbgCallParams.erase(Icsp); + } + + DbgCallMap::iterator Ics = DbgCallSites.find(Node); + if (Ics != DbgCallSites.end()) { + for (auto &Val : Ics->second) + Val->setIsInvalidated(); + DbgCallSites.erase(Ics); + } } void SelectionDAG::DeallocateNode(SDNode *N) { @@ -7898,6 +7912,19 @@ SDDbgValue(Var, Expr, VReg, IsIndirect, DL, O, SDDbgValue::VREG); } +void SelectionDAG::AddDbgCallSite(SDDbgCallSite *CS, const SDNode *SD) { + DbgInfo->add(CS, SD); +} + +void SelectionDAG::AddDbgCallParam(SDDbgCallSite *CS, SDDbgCallSiteParam *CSP, + SDNode *SD) { + if (SD) { + SD->setHasDebugCallParam(true); + DbgInfo->add(CSP, SD); + } + CS->addCallSiteParam(CSP); +} + void SelectionDAG::transferDbgValues(SDValue From, SDValue To, unsigned OffsetInBits, unsigned SizeInBits, bool InvalidateDbg) { @@ -7911,6 +7938,21 @@ if (From == To || FromNode == ToNode) return; + if (FromNode->getHasDebugCallParam()) { + ArrayRef SDCSPs = GetDbgCallParam(FromNode); + for (auto SDCSP : SDCSPs) { + if (SDCSP->getKind() == SDDbgCallSiteParam::SDNODE && + SDCSP->getSDNode() == FromNode && + SDCSP->getResNo() == From.getResNo() && !SDCSP->isInvalidated()) { + SDDbgCallSiteParam *newParam = getDbgCallSiteParam( + SDCSP->getCallSiteParam(), ToNode, To.getResNo(), SDCSP->getReg(), + SDCSP->getOrder(), SDCSP->getParent()); + SDCSP->setIsInvalidated(); + AddDbgCallParam(SDCSP->getParent(), newParam, ToNode); + } + } + } + if (!FromNode->getHasDebugValue()) return; @@ -8008,6 +8050,35 @@ return new (DbgInfo->getAlloc()) SDDbgLabel(Label, DL, O); } +SDDbgCallSiteParam *SelectionDAG::getDbgCallSiteParam(MDNode *CSP, SDNode *N, + unsigned Res, uint64_t R, + unsigned O, + SDDbgCallSite *SDC) { + return new (DbgInfo->getAlloc()) SDDbgCallSiteParam(CSP, N, Res, R, O, SDC); +} + +SDDbgCallSiteParam * +SelectionDAG::getDbgCallSiteFrameParam(MDNode *CSP, unsigned FI, uint64_t Reg, + unsigned O, SDDbgCallSite *SDC) { + return new (DbgInfo->getAlloc()) SDDbgCallSiteParam(CSP, FI, Reg, O, SDC); +} + +SDDbgCallSiteParam * +SelectionDAG::getConstantDbgCallParam(MDNode *CSP, const Value *C, uint64_t Reg, + unsigned O, SDDbgCallSite *SDC) { + return new (DbgInfo->getAlloc()) SDDbgCallSiteParam(CSP, C, Reg, O, SDC); +} + +/// Creates a SDDbgCallSite node. +SDDbgCallSite *SelectionDAG::getDbgCallSite(DICallSite *CS, uint64_t isTailCall, + uint64_t regCS, + const DebugLoc &DL, + unsigned O) { + assert(cast(CS)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return new (DbgInfo->getAlloc())SDDbgCallSite(CS, isTailCall, regCS, DL, O); +} + namespace { /// RAUWUpdateListener - Helper for ReplaceAllUsesWith - When the node Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -724,6 +724,10 @@ bool isExportableFromCurrentBlock(const Value *V, const BasicBlock *FromBB); void CopyToExportRegsIfNeeded(const Value *V); void ExportFromCurrentBlock(const Value *V); + void collectCallDebugInfo(ImmutableCallSite CS, + TargetLowering::CallLoweringInfo &CLI, + DICallSite *CallSiteMD); + void LowerCallTo(ImmutableCallSite CS, SDValue Callee, bool IsTailCall, const BasicBlock *EHPadBB = nullptr); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6641,6 +6641,200 @@ return Result; } +template +static DICallSiteParam *getMatchingParam(const TargetLowering::ArgListTy &Args, + const NodeType *MatchingParam, + BitVector &ProcessedParams, + DICallSite *CallSite) { + + int currentParam = ProcessedParams.find_first(); + do { + SDNode *ArgNode = Args[currentParam].Node.getNode(); + if (ArgNode == MatchingParam) + break; + if (std::is_same::value) { + if (isa(ArgNode) && + cast(ArgNode)->getIndex() == + cast(MatchingParam)->getIndex()) + break; + } else if (std::is_same::value) { + if (isa(ArgNode)) { + const ConstantSDNode *ArgNodeTmp = cast(ArgNode); + const ConstantSDNode *MatchingTmp = cast(MatchingParam); + const ConstantInt *CIArg = ArgNodeTmp->getConstantIntValue(); + const ConstantInt *CIMat = MatchingTmp->getConstantIntValue(); + unsigned CIArgBw = CIArg->getBitWidth(); + unsigned CIMatBw = CIMat->getBitWidth(); + + // We need to check for same constant values that have different + // types. For example 8 can be represented as i8 and as i32. + if (CIArgBw <= 64 && CIMatBw <= 64 && + CIArg->getSExtValue() == CIMat->getSExtValue()) + break; + else if (CIArgBw == CIMatBw && CIArg->getValue() == CIMat->getValue()) + break; + } + } else { + unsigned Opcode = MatchingParam->getOpcode(); + if ((Opcode == ISD::SIGN_EXTEND || Opcode == ISD::ZERO_EXTEND || + Opcode == ISD::ANY_EXTEND || Opcode == ISD::FP_EXTEND) && + // We can have situation like + // MatchingParam : t17: i32 = zero_extend t8 + // ArgNode : t9: i8 = zero_extend t8 + (MatchingParam->getOperand(0).getNode() == ArgNode || + (Opcode == ArgNode->getOpcode() && + MatchingParam->getOperand(0).getNode() == + ArgNode->getOperand(0).getNode()))) { + break; + } else if (Opcode == ISD::BUILD_VECTOR) { + if (MatchingParam->getOperand(0)->getOpcode() == + ISD::EXTRACT_VECTOR_ELT && + MatchingParam->getOperand(0)->getOperand(0).getNode() == ArgNode) + break; + } else if (ArgNode->getOpcode() == ISD::TRUNCATE) + if (ArgNode->getOperand(0).getNode() == MatchingParam) + break; + } + currentParam = ProcessedParams.find_next(currentParam); + } while (currentParam >= 0); + + // If currentParam is higher or equal than zero that means + // that we hit break in previous loop meaning that we have + // found matcing param with index currentParam. + if (currentParam >= 0) { + auto Params = CallSite->getParameters(); + ProcessedParams.flip(currentParam); + return cast(Params[currentParam]); + } + + return nullptr; +} + +void SelectionDAGBuilder::collectCallDebugInfo( + ImmutableCallSite CS, TargetLowering::CallLoweringInfo &CLI, + DICallSite *CallSiteMD) { + SDDbgCallSite *SDV; + uint64_t regCS = 0; + DebugLoc DL = getCurDebugLoc(); + if (const llvm::CallInst *Call = + dyn_cast(CS.getInstruction())) { + // If we do not have called subprogram DISubprogram that means that + // this call is call to indirect function through register. + if (!(CallSiteMD->getCalledSubprogram())) { + const Value *V = Call->getCalledValue(); + SDValue N = NodeMap[V]; + if (N.getNode()) + regCS = getUnderlyingArgReg(N); + // FIXME: If regCS is zero that means that this is actually global address + // and we are acutally having dirct call. This happend due to inlining. + // More appropriate place to handle this is inliner pass. + if (!regCS) { + auto *F = Call->getCalledFunction(); + if (F) + CallSiteMD = DICallSite::get( + CallSiteMD->getContext(), DL->getScope(), CallSiteMD->getFile(), + CallSiteMD->getParameters(), DL->getLine(), F->getSubprogram()); + } + } + } + + SDV = DAG.getDbgCallSite(CallSiteMD, CLI.IsTailCall, regCS, DL, SDNodeOrder); + SDNode *EndOfCall = nullptr; + SmallVector CallSiteNodes; + for (SDNode *ArgNodes = CLI.Chain.getNode(); ArgNodes != nullptr; + ArgNodes = ArgNodes->getGluedNode()) { + switch (ArgNodes->getOpcode()) { + case ISD::CALLSEQ_END: + EndOfCall = ArgNodes; + continue; + case ISD::CALLSEQ_START: + break; + case ISD::CopyToReg: + CallSiteNodes.push_back(ArgNodes); + default: + continue; + } + } + + TargetLowering::ArgListTy &Args = CLI.getArgs(); + BitVector ProcessedParams(Args.size(), true); + CalleeSavedRegChecker CalleeSavedRegs(&CLI.DAG.getMachineFunction()); + + while (ProcessedParams.any() && !CallSiteNodes.empty()) { + SDNode *ParamNode = CallSiteNodes.back(); + CallSiteNodes.pop_back(); + SDDbgCallSiteParam *SDCSP = nullptr; + // Add check that it is X86 target + if (CallSiteNodes.empty() && CLI.IsVarArg) + break; + unsigned TransferReg = + cast(ParamNode->getOperand(1))->getReg(); + unsigned ResNo = ParamNode->getOperand(2).getResNo(); + + unsigned currentParam = ProcessedParams.find_first(); + ParamNode = ParamNode->getOperand(2).getNode(); + bool isUndef = + // Check whether current node or arg node is undef + (ParamNode->isUndef() || Args[currentParam].Node.isUndef()) || + // Check whether current node is merged node of undefs + ((ParamNode->getOpcode() == ISD::MERGE_VALUES && + ParamNode->getOperand(0)->isUndef()) && + // Check whether current arg node is merged node of undefs + (Args[currentParam].Node.getOpcode() == ISD::MERGE_VALUES && + Args[currentParam].Node.getOperand(0).isUndef())); + + if (isUndef) { + ProcessedParams.flip(currentParam); + continue; + } + + if (DAG.getTargetLoweringInfo().isGlobalBaseReg(ParamNode)) + continue; + // TODO : Check floats + if (ConstantSDNode *C = dyn_cast(ParamNode)) { + if (DICallSiteParam *DCSP = + getMatchingParam(Args, C, ProcessedParams, CallSiteMD)) { + const Value *V = CS.getArgument(DCSP->getArgNo() - 1); + if (!dyn_cast(V) && !dyn_cast(V)) + continue; + SDCSP = DAG.getConstantDbgCallParam( + DCSP, CS.getArgument(DCSP->getArgNo() - 1), TransferReg, + SDNodeOrder, SDV); + } + } else if (auto FINode = dyn_cast(ParamNode)) { + if (DICallSiteParam *DCSP = + getMatchingParam(Args, FINode, ProcessedParams, CallSiteMD)) + SDCSP = DAG.getDbgCallSiteFrameParam(DCSP, FINode->getIndex(), + TransferReg, SDNodeOrder, SDV); + } else if (DICallSiteParam *DCSP = getMatchingParam( + Args, ParamNode, ProcessedParams, CallSiteMD)) { + if (auto RegNode = dyn_cast(ParamNode)) { + unsigned Reg = RegNode->getReg(); + bool isPhysical = TargetRegisterInfo::isPhysicalRegister(Reg); + if (isPhysical && !CalleeSavedRegs.isCalleeSaved(RegNode->getReg())) + continue; + } + + SDCSP = DAG.getDbgCallSiteParam(DCSP, ParamNode, ResNo, TransferReg, + SDNodeOrder, SDV); + } + + if (!SDCSP) + continue; + DAG.AddDbgCallParam( + SDV, SDCSP, + SDCSP->getKind() == SDDbgCallSiteParam::SDNODE ? ParamNode : nullptr); + } + + if (EndOfCall) + DAG.AddDbgCallSite(SDV, EndOfCall); + else { + // Otherwise it is tail call. + SDV->setIsSpecialCallSite(); + DAG.AddDbgCallSite(SDV, CLI.Chain.getNode()); + } +} + void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, bool isTailCall, const BasicBlock *EHPadBB) { @@ -6714,6 +6908,10 @@ .setConvergent(CS.isConvergent()); std::pair Result = lowerInvokable(CLI, EHPadBB); + if (MDNode *CallSiteMD = + CS.getInstruction()->getMetadata(LLVMContext::MD_call_site)) + collectCallDebugInfo(CS, CLI, cast(CallSiteMD)); + if (Result.first.getNode()) { const Instruction *Inst = CS.getInstruction(); Result.first = lowerRangeToAssertZExt(DAG, *Inst, Result.first); Index: lib/CodeGen/TargetRegisterInfo.cpp =================================================================== --- lib/CodeGen/TargetRegisterInfo.cpp +++ lib/CodeGen/TargetRegisterInfo.cpp @@ -457,6 +457,12 @@ return true; } +CalleeSavedRegChecker::CalleeSavedRegChecker(const MachineFunction *MF) { + const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); + CallSavedRegs = + TRI->getCallPreservedMask(*MF, MF->getFunction().getCallingConv()); +} + unsigned TargetRegisterInfo::getRegSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI) const { const TargetRegisterClass *RC{}; Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -1303,6 +1303,8 @@ bool mayBeEmittedAsTailCall(const CallInst *CI) const override; + bool isGlobalBaseReg(SDNode *N) const override; + EVT getTypeForExtReturn(LLVMContext &Context, EVT VT, ISD::NodeType ExtendKind) const override; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2957,6 +2957,10 @@ return true; } +bool X86TargetLowering::isGlobalBaseReg(SDNode *N) const { + return N->getOpcode() == X86ISD::GlobalBaseReg; +} + SDValue X86TargetLowering::LowerMemArgument(SDValue Chain, CallingConv::ID CallConv, const SmallVectorImpl &Ins, Index: test/DebugInfo/X86/call-site-param-expr.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/call-site-param-expr.ll @@ -0,0 +1,95 @@ +; RUN: llc %s -stop-after="expand-isel-pseudos" -o -| FileCheck %s +; +; extern void foo(int *a, int b, int c, int d, int e, int f); +; extern int getVal(); +; +; void baa(int arg1, int arg2, int arg3) { +; int local1 = getVal(); +; foo(&local1, arg2, 10, 15, arg3 + 3, arg1 + arg2); +; } +; +; CHECK: CALL64pcrel32 @getVal +; CHECK-NEXT: DBG_CALLSITE 0, $noreg, !14 +; CHECK-NOT: DBG_CALLSITEPARAM +; CHECK: %[[VREG1:[0-9]+]]:gr64 = LEA64r %[[VREG1VAL:.*]], 1, $noreg, 0, $noreg +; CHECK-NEXT: %[[VREG3:[0-9]+]]:gr32 = MOV32ri [[VREG3VAL:[0-9]+]] +; CHECK-NEXT: %[[VREG4:[0-9]+]]:gr32 = MOV32ri [[VREG4VAL:[0-9]+]] +; CHECK-NEXT: $[[ARG1REG:[a-z]+]] = COPY %[[VREG1]] +; CHECK-NEXT: $[[ARG2REG:[a-z]+]] = COPY %[[VREG2:[0-9]+]] +; CHECK-NEXT: $[[ARG3REG:[a-z]+]] = COPY %[[VREG3]] +; CHECK-NEXT: $[[ARG4REG:[a-z]+]] = COPY %[[VREG4]] +; CHECK-NEXT: $[[ARG5REG:[a-z8]+]] = COPY %[[VREG5:[0-9]+]] +; CHECK-NEXT: $[[ARG6REG:[a-z9]+]] = COPY %[[VREG6:[0-9]+]] +; CHECK-NEXT: CALL64pcrel32 @foo +; CHECK-NEXT: DBG_CALLSITE 0, $noreg, !16 +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG1REG]], !18, %[[VREG1VAL]], 0 +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG2REG]], !19, %[[VREG2]] +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG3REG]], !20, [[VREG3VAL]] +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG4REG]], !21, [[VREG4VAL]] +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG5REG]], !22, %[[VREG5]] +; CHECK-NEXT: DBG_CALLSITEPARAM $[[ARG6REG]], !23, %[[VREG6]] + +; ModuleID = 'call-site-param-expr.c' +source_filename = "call-site-param-expr.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @baa(i32 %arg1, i32 %arg2, i32 %arg3) local_unnamed_addr !dbg !6 { +entry: + %local1 = alloca i32, align 4 + %0 = bitcast i32* %local1 to i8*, !dbg !25 + call void @llvm.lifetime.start(i64 4, i8* nonnull %0), !dbg !25 + %call = tail call i32 (...) @getVal(), !dbg !25, !call_site !14 + store i32 %call, i32* %local1, align 4, !dbg !25, !tbaa !26 + %add = add nsw i32 %arg3, 3, !dbg !25 + %add1 = add nsw i32 %arg2, %arg1, !dbg !25 + call void @foo(i32* nonnull %local1, i32 %arg2, i32 10, i32 15, i32 %add, i32 %add1), !dbg !25, !call_site !16 + call void @llvm.lifetime.end(i64 4, i8* nonnull %0), !dbg !25 + ret void, !dbg !25 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start(i64, i8* nocapture) + +declare i32 @getVal(...) local_unnamed_addr + +declare void @foo(i32*, i32, i32, i32, i32, i32) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "call-site-param-expr.c", directory: "/") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0"} +!6 = distinct !DISubprogram(name: "baa", scope: !1, file: !1, line: 11, type: !7, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{null, !9, !9, !9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11, !12, !13, !14, !16} +!11 = !DILocalVariable(name: "arg3", arg: 3, scope: !6, file: !1, line: 11, type: !9) +!12 = !DILocalVariable(name: "arg2", arg: 2, scope: !6, file: !1, line: 11, type: !9) +!13 = !DILocalVariable(name: "local1", scope: !6, file: !1, line: 12, type: !9) +!14 = !DICallSite(scope: !6, file: !1, parameters: !2, line: 12, calledSubprogram: !15) +!15 = !DISubprogram(name: "getVal", scope: !1, file: !1, line: 9, isLocal: false, isDefinition: false, isOptimized: true, retainedNodes: !2) +!16 = !DICallSite(scope: !6, file: !1, parameters: !17, line: 13, calledSubprogram: !24) +!17 = !{!18, !19, !20, !21, !22, !23} +!18 = !DICallSiteParam(argno: 1, variable: !13, expr: !DIExpression(DW_OP_push_object_address)) +!19 = !DICallSiteParam(argno: 2, variable: !12, expr: !DIExpression()) +!20 = !DICallSiteParam(argno: 3, expr: !DIExpression(DW_OP_lit10)) +!21 = !DICallSiteParam(argno: 4, expr: !DIExpression(DW_OP_lit15)) +!22 = !DICallSiteParam(argno: 5, variable: !11, expr: !DIExpression(DW_OP_lit3, DW_OP_plus)) +!23 = !DICallSiteParam(argno: 6, expr: !DIExpression()) +!24 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 8, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) +!25 = !DILocation(line: 11, column: 14, scope: !6) +!26 = !{!27, !27, i64 0} +!27 = !{!"int", !28, i64 0} +!28 = !{!"omnipotent char", !29, i64 0} +!29 = !{!"Simple C/C++ TBAA"}