Index: lib/CodeGen/LiveDebugValues.cpp =================================================================== --- lib/CodeGen/LiveDebugValues.cpp +++ lib/CodeGen/LiveDebugValues.cpp @@ -66,6 +66,9 @@ STATISTIC(NumInserted, "Number of DBG_VALUE instructions inserted"); +static cl::opt EmitEntryDbgValues("emit-entry-values", cl::Hidden, + cl::init(false)); + // If @MI is a DBG_VALUE with debug value described by a defined // register, returns the number of this register. In the other case, returns 0. static unsigned isDbgValueDescribedByReg(const MachineInstr &MI) { @@ -143,7 +146,8 @@ enum VarLocKind { InvalidKind = 0, RegisterKind, - SpillLocKind + SpillLocKind, + EntryValueKind } Kind = InvalidKind; /// The value location. Stored separately to avoid repeatedly @@ -154,15 +158,16 @@ uint64_t Hash; } Loc; - VarLoc(const MachineInstr &MI, LexicalScopes &LS) + VarLoc(const MachineInstr &MI, LexicalScopes &LS, VarLocKind K = InvalidKind) : Var(MI.getDebugVariable(), MI.getDebugLoc()->getInlinedAt()), MI(MI), - UVS(MI.getDebugLoc(), LS) { + UVS(MI.getDebugLoc(), LS), Kind(K) { static_assert((sizeof(Loc) == sizeof(uint64_t)), "hash does not cover all members of Loc"); assert(MI.isDebugValue() && "not a DBG_VALUE"); assert(MI.getNumOperands() == 4 && "malformed DBG_VALUE"); if (int RegNo = isDbgValueDescribedByReg(MI)) { - Kind = RegisterKind; + if (Kind != EntryValueKind) + Kind = RegisterKind; Loc.RegNo = RegNo; } } @@ -186,6 +191,10 @@ return 0; } + bool isEntryValueKind() const { + return Kind == EntryValueKind; + } + /// Determine whether the lexical scope of this value's debug location /// dominates MBB. bool dominates(MachineBasicBlock &MBB) const { return UVS.dominates(&MBB); } @@ -195,17 +204,23 @@ #endif bool operator==(const VarLoc &Other) const { - return Var == Other.Var && Loc.Hash == Other.Loc.Hash; + return Var == Other.Var && + Loc.Hash == Other.Loc.Hash && Kind == Other.Kind; } /// This operator guarantees that VarLocs are sorted by Variable first. bool operator<(const VarLoc &Other) const { - if (Var == Other.Var) - return Loc.Hash < Other.Loc.Hash; + if (Var == Other.Var) { + if (Other.Kind == Kind) + return Loc.Hash < Other.Loc.Hash; + return Other.Kind < Kind; + } + return Var < Other.Var; } }; + using ParamSet = SmallVector; using VarLocMap = UniqueVector; using VarLocSet = SparseBitVector<>; using VarLocInMBB = SmallDenseMap; @@ -282,15 +297,27 @@ VarLocMap &VarLocIDs); void transferSpillOrRestoreInst(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, TransferMap &Transfers); + void emitEntryValues(MachineInstr &MI, OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, TransferMap &Transfers, + ParamSet &ParamEntryVals, + SparseBitVector<> &KillSet); void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, TransferMap &Transfers); void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, - const VarLocMap &VarLocIDs); + VarLocMap &VarLocIDs, TransferMap &Transfers, + ParamSet &ParamEntryVals); + void adjustCallSites(MachineInstr &MI, OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, + ParamSet &DeadCallParams, + bool transferingChanges); bool transferTerminatorInst(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs); bool process(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, - TransferMap &Transfers, bool transferChanges); + TransferMap &Transfers, + ParamSet &DeadCallParams, + ParamSet &ParamEntryVals, + bool transferChanges); bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs, const VarLocMap &VarLocIDs, @@ -409,13 +436,69 @@ // Add the VarLoc to OpenRanges from this DBG_VALUE. // TODO: Currently handles DBG_VALUE which has only reg as location. + // Currently, this also handles entry values and constants from + // 'Tracking parameters entry values' approach. + VarLoc::VarLocKind K = VarLoc::InvalidKind; if (isDbgValueDescribedByReg(MI)) { - VarLoc VL(MI, LS); + K = VarLoc::RegisterKind; + const DIExpression *Expr = MI.getDebugExpression(); + for (auto I = Expr->expr_op_begin(), E = Expr->expr_op_end(); I != E; I++) + if (I->getOp() == dwarf::DW_OP_GNU_entry_value) + K = VarLoc::EntryValueKind; + } + + if (K != VarLoc::InvalidKind) { + VarLoc VL(MI, LS, K); unsigned ID = VarLocIDs.insert(VL); OpenRanges.insert(ID, VL.Var); } } +void LiveDebugValues::emitEntryValues( + MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, + TransferMap &Transfers, ParamSet &ParamEntryVals, + SparseBitVector<> &KillSet) { + MachineFunction *MF = MI.getParent()->getParent(); + for (unsigned ID : KillSet) { + if (VarLocIDs[ID].Var.getVar() && + VarLocIDs[ID].Var.getVar()->isParameter()) { + const MachineInstr *CurrDMI = &VarLocIDs[ID].MI; + auto DMI = std::find_if( + ParamEntryVals.begin(), ParamEntryVals.end(), + [&CurrDMI](MachineInstr *MII) { + return CurrDMI->getDebugVariable() == MII->getDebugVariable(); + }); + + // If parameter DBG_VALUE is not in vector that means that its value + // is changed trough course of function. That means that we can't + // use parameter entry value. + if (DMI == ParamEntryVals.end()) + continue; + + auto finishEntryValue = [&](MachineInstr *NewDMI, VarLoc::VarLocKind K) { + if ((*DMI)->isIndirectDebugValue()) + NewDMI->getOperand(1).setImm((*DMI)->getOperand(1).getImm()); + + TransferDebugPair MIP = {&MI, NewDMI}; + Transfers.push_back(MIP); + VarLoc VL(*NewDMI, LS, K); + unsigned EntryValLocID = VarLocIDs.insert(VL); + OpenRanges.insert(EntryValLocID, VL.Var); + }; + + DIExpression *NewExpr = + DIExpression::prepend((*DMI)->getDebugExpression(), false, 0, false, + false, DIExpression::WithEntryValue); + MachineInstr *EntryValDbgMI = BuildMI( + *MF, (*DMI)->getDebugLoc(), (*DMI)->getDesc(), + (*DMI)->isIndirectDebugValue(), (*DMI)->getOperand(0).getReg(), + (*DMI)->getDebugVariable(), NewExpr); + + finishEntryValue(EntryValDbgMI, VarLoc::EntryValueKind); + } + } +} + /// Create new TransferDebugPair and insert it in \p Transfers. The VarLoc /// with \p OldVarID should be deleted form \p OpenRanges and replaced with /// new VarLoc. If \p NewReg is different than default zero value then the @@ -492,9 +575,9 @@ } /// A definition of a register may mark the end of a range. -void LiveDebugValues::transferRegisterDef(MachineInstr &MI, - OpenRangesSet &OpenRanges, - const VarLocMap &VarLocIDs) { +void LiveDebugValues::transferRegisterDef( + MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, + TransferMap &Transfers, ParamSet &ParamEntryVals) { MachineFunction *MF = MI.getMF(); const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); @@ -524,6 +607,9 @@ } } OpenRanges.erase(KillSet, VarLocIDs); + if (EmitEntryDbgValues) + emitEntryValues(MI, OpenRanges, VarLocIDs, Transfers, ParamEntryVals, + KillSet); } /// Decide if @MI is a spill instruction and return true if it is. We use 2 @@ -708,13 +794,64 @@ return Changed; } +/// Only in first call for every instruction, which is indicated when +/// /p transferingChanges is set to false, we fill DeadCallParams with +/// all non constant call site parameter locations (locations that +/// depend on a variable). Call site parameter descriptions that have +/// different first register operand (register that carry function +/// argument) and second register operand (register that is loaded into +/// argument carrying register) are excused from being candidates of +/// deleting. Remaining parameters descriptions are candidates for deleting +/// until we find proper DBG_VALUE that describes variable on which call +/// site parameter depends. Proper DBG_VALUE is the one that is still +/// valid (non clobered location) when we step on call site parameter +/// that depends on it. +void LiveDebugValues::adjustCallSites( + MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, + ParamSet &DeadCallParams, bool transferingChanges) { + if (!MI.isDebugCallSite()) + return; + if (!transferingChanges) { + auto It = MI.getIterator(); + while (It->isBundledWithSucc()) { + It++; + if (It->getDebugCallSiteParam()->getVar() && It->getOperand(2).isReg() && + !It->getOperand(2).getReg()) + DeadCallParams.push_back(&*It); + } + } + + if (DeadCallParams.empty()) + return; + + auto It = MI.getIterator(); + while (It->isBundledWithSucc()) { + It++; + const DICallSiteParam *DCSP = It->getDebugCallSiteParam(); + for (unsigned ID : OpenRanges.getVarLocs()) { + const DILocalVariable *DLV = VarLocIDs[ID].Var.getVar(); + if (DCSP->getVar() == DLV) + for (auto I = DeadCallParams.begin(), E = DeadCallParams.end(); I != E; + I++) + if (*I == &*It) + DeadCallParams.erase(I); + } + } +} + /// This routine creates OpenRanges and OutLocs. bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, - TransferMap &Transfers, bool transferChanges) { + TransferMap &Transfers, + ParamSet &DeadCallParams, + ParamSet &ParamEntryVals, + bool transferChanges) { bool Changed = false; transferDebugValue(MI, OpenRanges, VarLocIDs); - transferRegisterDef(MI, OpenRanges, VarLocIDs); + transferRegisterDef(MI, OpenRanges, VarLocIDs, Transfers, + ParamEntryVals); + adjustCallSites(MI, OpenRanges, VarLocIDs, DeadCallParams, + transferChanges); if (transferChanges) { transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers); transferSpillOrRestoreInst(MI, OpenRanges, VarLocIDs, Transfers); @@ -810,6 +947,7 @@ BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(), DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(), DMI->getDebugVariable(), DMI->getDebugExpression()); + if (DMI->isIndirectDebugValue()) MI->getOperand(1).setImm(DMI->getOperand(1).getImm()); LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump();); @@ -850,15 +988,57 @@ enum : bool { dontTransferChanges = false, transferChanges = true }; + ParamSet DeadCallParams; + ParamSet ParamEntryVals; + MachineBasicBlock &First_MBB = *(MF.begin()); + + for (auto &MI : First_MBB) + if (MI.isDebugValue() && MI.getDebugVariable()->isParameter() && + MI.getDebugVariable()->isNotChanged() && + !MI.getDebugLoc()->getInlinedAt()) { + // Enter DEBUG_VALUE instructions that track parameters into ParamEntryVals. + // When we encounter a variable that we have already entered, we assume + // that we have found all parameter entry locations and stop. + // Note: We check whether MI is inlined in order to deduce whether the variable that it tracks + // twhether the variable that it tracks comes from a different function. + // If that is the case we can't track its entry value. + + auto IsNewParameter = [&ParamEntryVals](const MachineInstr &MI) { + for (auto MII : ParamEntryVals) + if (MII->getDebugVariable() == MI.getDebugVariable()) + return false; + return true; + }; + + if (IsNewParameter(MI)) + ParamEntryVals.push_back(&MI); + else + break; + } + // Initialize every mbb with OutLocs. // We are not looking at any spill instructions during the initial pass // over the BBs. The LiveDebugVariables pass has already created DBG_VALUE // instructions for spills of registers that are known to be user variables // within the BB in which the spill occurs. - for (auto &MBB : MF) + for (auto &MBB : MF) { for (auto &MI : MBB) - process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, - dontTransferChanges); + process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, DeadCallParams, + ParamEntryVals, dontTransferChanges); + // Add any entry DBG_VALUE instructions necessitated by parameter + // clobbering. + for (auto &TR : Transfers) { + MachineBasicBlock::instr_iterator InstAfter = + (*(TR.TransferInst)).getIterator(); + MBB.insertAfter(InstAfter, TR.DebugInst); + if (InstAfter->isBundledWithSucc()) { + TR.DebugInst->setFlag(MachineInstr::BundledSucc); + TR.DebugInst->setFlag(MachineInstr::BundledPred); + } + } + + Transfers.clear(); + } auto hasNonArtificialLocation = [](const MachineInstr &MI) -> bool { if (const DebugLoc &DL = MI.getDebugLoc()) @@ -905,12 +1085,18 @@ // correspond to user variables. for (auto &MI : *MBB) OLChanged |= process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, - transferChanges); + DeadCallParams, ParamEntryVals, transferChanges); // Add any DBG_VALUE instructions necessitated by spills. - for (auto &TR : Transfers) - MBB->insertAfter(MachineBasicBlock::iterator(*TR.TransferInst), - TR.DebugInst); + for (auto &TR : Transfers) { + MachineBasicBlock::instr_iterator InstAfter = (*(TR.TransferInst)).getIterator(); + MBB->insertAfter(InstAfter, TR.DebugInst); + if (InstAfter->isBundledWithSucc()) { + TR.DebugInst->setFlag(MachineInstr::BundledSucc); + TR.DebugInst->setFlag(MachineInstr::BundledPred); + } + } + Transfers.clear(); LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs, @@ -933,6 +1119,12 @@ assert(Pending.empty() && "Pending should be empty"); } + // Erase all call site parameters for which we didn't find proper + // DBG_VALUE that it depends on. + for(auto It : DeadCallParams) + It->eraseFromBundle(); + DeadCallParams.clear(); + LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs, "Final OutLocs", dbgs())); LLVM_DEBUG(printVarLocInMBB(MF, InLocs, VarLocIDs, "Final InLocs", dbgs())); return Changed; Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -258,6 +258,14 @@ if (emitPseudoExpansionLowering(*OutStreamer, &*I)) continue; + if (I->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + PrintDebugValueComment(&*I, OS); + return; + } + if (I->getOpcode() == Mips::PseudoReturn || I->getOpcode() == Mips::PseudoReturn64 || I->getOpcode() == Mips::PseudoIndirectBranch || Index: test/DebugInfo/MIR/X86/dbginfo-entryvals.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbginfo-entryvals.mir @@ -0,0 +1,280 @@ +# RUN: llc -emit-entry-values=1 -run-pass=livedebugvalues -march=x86-64 -o - %s | FileCheck %s +# +# test.c +# +##include +##include +##include "ex.h" +# +#__attribute__((noinline)) +#void +#fn1 (int x, int y) { +# int u = x + y; +# if (x > 1) +# u += 1; +# else +# u += 2; +# int a = 7; +# fn2 (a); +# u --; +#} +# +#int main() +#{ +# int l = 4, k =7; +# fn1 (l, k); +# +# return 0; +#} +# +# ex.h +##include +##include +# +#__attribute__((noinline)) +#void +#fn2 (int a) { +# printf("The num is %d\n", a); +# abort(); +# a++; +#} +# +# CHECK: DBG_VALUE $edi, $noreg, !30, !DIExpression(DW_OP_GNU_entry_value), debug-location {{.*}} +# CHECK: DBG_VALUE $esi, $noreg, !31, !DIExpression(DW_OP_GNU_entry_value), debug-location {{.*}} +# +--- | + ; ModuleID = 'test.ll' + source_filename = "test.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @.str = private unnamed_addr constant [15 x i8] c"The num is %d\0A\00", align 1 + + ; Function Attrs: noinline noreturn nounwind uwtable + define void @fn2(i32 %a) local_unnamed_addr !dbg !6 { + entry: + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !DIExpression()), !dbg !22 + %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i64 0, i64 0), i32 %a), !dbg !23, !CallSite !13 + tail call void @abort(), !dbg !24, !CallSite !19 + unreachable, !dbg !24 + } + + ; Function Attrs: nounwind + declare i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr + + ; Function Attrs: noreturn nounwind + declare void @abort() local_unnamed_addr + + ; Function Attrs: noinline noreturn nounwind uwtable + define void @fn1(i32 %x, i32 %y) local_unnamed_addr !dbg !25 { + entry: + tail call void @llvm.dbg.value(metadata i32 %x, i64 0, metadata !30, metadata !DIExpression()), !dbg !36 + tail call void @llvm.dbg.value(metadata i32 %y, i64 0, metadata !31, metadata !DIExpression()), !dbg !37 + tail call void @llvm.dbg.value(metadata i32 7, i64 0, metadata !29, metadata !DIExpression()), !dbg !38 + tail call void @fn2(i32 7), !dbg !39, !CallSite !33 + unreachable + } + + ; Function Attrs: noreturn nounwind uwtable + define i32 @main() local_unnamed_addr !dbg !40 { + entry: + tail call void @llvm.dbg.value(metadata i32 4, i64 0, metadata !45, metadata !DIExpression()), !dbg !50 + tail call void @llvm.dbg.value(metadata i32 7, i64 0, metadata !44, metadata !DIExpression()), !dbg !51 + tail call void @fn1(i32 4, i32 7), !dbg !52, !CallSite !46 + unreachable + } + + ; Function Attrs: nounwind readnone + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "test.c", directory: "/dir") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 8.0.0"} + !6 = distinct !DISubprogram(name: "fn2", scope: !7, file: !7, line: 6, type: !8, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11) + !7 = !DIFile(filename: "./ex.h", directory: "/dir") + !8 = !DISubroutineType(types: !9) + !9 = !{null, !10} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !{!12, !13, !19} + !12 = !DILocalVariable(name: "a", arg: 1, scope: !6, file: !7, line: 6, type: !10) + !13 = !DICallSite(scope: !6, file: !7, parameters: !14, line: 8, calledSubprogram: !17) + !14 = !{!15, !16} + !15 = !DICallSiteParam(argno: 1, expr: !DIExpression()) + !16 = !DICallSiteParam(argno: 2, variable: !12, expr: !DIExpression()) + !17 = !DISubprogram(name: "printf", scope: !18, file: !18, line: 361, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) + !18 = !DIFile(filename: "/usr/include/stdio.h", directory: "/dir") + !19 = !DICallSite(scope: !6, file: !7, parameters: !2, line: 9, calledSubprogram: !20) + !20 = !DISubprogram(name: "abort", scope: !21, file: !21, line: 514, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true, retainedNodes: !2) + !21 = !DIFile(filename: "/usr/include/stdlib.h", directory: "/dir") + !22 = !DILocation(line: 6, column: 10, scope: !6) + !23 = !DILocation(line: 8, column: 5, scope: !6) + !24 = !DILocation(line: 9, column: 5, scope: !6) + !25 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 7, type: !26, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !28) + !26 = !DISubroutineType(types: !27) + !27 = !{null, !10, !10} + !28 = !{!29, !30, !31, !32, !33} + !29 = !DILocalVariable(name: "a", scope: !25, file: !1, line: 17, type: !10) + !30 = !DILocalVariable(name: "x", arg: 1, scope: !25, file: !1, line: 7, type: !10, flags: DIFlagVariableNotChanged) + !31 = !DILocalVariable(name: "y", arg: 2, scope: !25, file: !1, line: 7, type: !10, flags: DIFlagVariableNotChanged) + !32 = !DILocalVariable(name: "u", scope: !25, file: !1, line: 9, type: !10) + !33 = !DICallSite(scope: !25, file: !1, parameters: !34, line: 19, calledSubprogram: !6) + !34 = !{!35} + !35 = !DICallSiteParam(argno: 1, variable: !29, expr: !DIExpression()) + !36 = !DILocation(line: 7, column: 10, scope: !25) + !37 = !DILocation(line: 7, column: 17, scope: !25) + !38 = !DILocation(line: 17, column: 9, scope: !25) + !39 = !DILocation(line: 19, column: 5, scope: !25) + !40 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 24, type: !41, isLocal: false, isDefinition: true, scopeLine: 25, isOptimized: true, unit: !0, retainedNodes: !43) + !41 = !DISubroutineType(types: !42) + !42 = !{!10} + !43 = !{!44, !45, !46} + !44 = !DILocalVariable(name: "k", scope: !40, file: !1, line: 26, type: !10) + !45 = !DILocalVariable(name: "l", scope: !40, file: !1, line: 26, type: !10) + !46 = !DICallSite(scope: !40, file: !1, parameters: !47, line: 28, calledSubprogram: !25) + !47 = !{!48, !49} + !48 = !DICallSiteParam(argno: 1, variable: !45, expr: !DIExpression()) + !49 = !DICallSiteParam(argno: 2, variable: !44, expr: !DIExpression()) + !50 = !DILocation(line: 26, column: 9, scope: !40) + !51 = !DILocation(line: 26, column: 16, scope: !40) + !52 = !DILocation(line: 28, column: 5, scope: !40) + +... +--- +name: fn2 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +liveins: + - { reg: '$edi' } +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 8 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + liveins: $edi + + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + DBG_VALUE debug-use $edi, debug-use $noreg, !12, !DIExpression(), debug-location !22 + $ecx = MOV32rr $edi + DBG_VALUE debug-use $ecx, debug-use $noreg, !12, !DIExpression(), debug-location !22 + dead $edi = MOV32ri @.str, implicit-def $rdi, debug-location !23 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !23 + $esi = MOV32rr killed $ecx, debug-location !23 + DBG_VALUE debug-use $esi, debug-use $noreg, !12, !DIExpression(), debug-location !22 + CALL64pcrel32 @printf, csr_64, implicit $rsp, implicit $rdi, implicit $esi, implicit killed $al, implicit-def $rsp, implicit-def dead $eax, debug-location !23 + DBG_CALLSITE 0, debug-use $noreg, !13, debug-location !23 { + DBG_CALLSITEPARAM debug-use $rdi, !15, @.str, debug-use $noreg, debug-location !23 + } + CALL64pcrel32 @abort, csr_64, implicit $rsp, implicit-def $rsp, debug-location !24 + DBG_CALLSITE 0, debug-use $noreg, !19, debug-location !24 + +... +--- +name: fn1 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 8 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp, debug-location !39 + CFI_INSTRUCTION def_cfa_offset 16 + DBG_VALUE debug-use $edi, debug-use $noreg, !30, !DIExpression(), debug-location !36 + DBG_VALUE debug-use $esi, debug-use $noreg, !31, !DIExpression(), debug-location !37 + DBG_VALUE 7, 0, !29, !DIExpression(), debug-location !38 + $edi = MOV32ri 7, debug-location !39 + CALL64pcrel32 @fn2, csr_64, implicit $rsp, implicit $edi, implicit-def $rsp, debug-location !39 + DBG_CALLSITE 0, debug-use $noreg, !33, debug-location !39 { + DBG_CALLSITEPARAM debug-use $edi, !35, 7, debug-use $noreg, debug-location !39 + } + +... +--- +name: main +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 8 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp, debug-location !52 + CFI_INSTRUCTION def_cfa_offset 16 + DBG_VALUE 4, 0, !45, !DIExpression(), debug-location !50 + DBG_VALUE 7, 0, !44, !DIExpression(), debug-location !51 + $edi = MOV32ri 4, debug-location !52 + $esi = MOV32ri 7, debug-location !52 + CALL64pcrel32 @fn1, csr_64, implicit $rsp, implicit killed $edi, implicit killed $esi, implicit-def $rsp, debug-location !52 + DBG_CALLSITE 0, debug-use $noreg, !46, debug-location !52 { + DBG_CALLSITEPARAM debug-use $edi, !48, 4, debug-use $noreg, debug-location !52 + DBG_CALLSITEPARAM debug-use $esi, !49, 7, debug-use $noreg, debug-location !52 + } + +...