Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2913,8 +2913,13 @@ /// Check if the expression consists of exactly one entry value operand. /// (This is the only configuration of entry values that is supported.) bool isEntryValue() const { - return getNumElements() > 0 && - getElement(0) == dwarf::DW_OP_LLVM_entry_value; + // Entry value can appear anywhere in expression. + for (size_t i = 0; i < getNumElements(); i++) { + if (getElement(i) == dwarf::DW_OP_LLVM_entry_value) { + return true; + } + } + return false; } /// Try to shorten an expression with an initial constant operand. Index: llvm/include/llvm/Transforms/Utils/DebugEntryValues.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Utils/DebugEntryValues.h @@ -0,0 +1,16 @@ +#ifndef LLVM_TRANSFORMS_UTILS_DEBUG_ENTRY_VALUES_H +#define LLVM_TRANSFORMS_UTILS_DEBUG_ENTRY_VALUES_H + +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" + +namespace llvm { +void markEntryValues(Function &F); +} // namespace llvm + +struct DebugEntryValues : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Function &F, + llvm::FunctionAnalysisManager &AM); +}; + +#endif // LLVM_TRANSFORMS_UTILS_DEBUG_ENTRY_VALUES_H Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -390,6 +390,10 @@ DIExpressionCursor &ExprCursor) { auto Op = ExprCursor.take(); (void)Op; + if (Op->getOp() != dwarf::DW_OP_LLVM_entry_value) { + // TODO: Handle this kind of entry-value expression. + Op = ExprCursor.take(); + } assert(Op && Op->getOp() == dwarf::DW_OP_LLVM_entry_value); assert(!IsEmittingEntryValue && "Already emitting entry value?"); assert(Op->getArg(0) == 1 && Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1141,12 +1141,11 @@ break; } case dwarf::DW_OP_LLVM_entry_value: { - // An entry value operator must appear at the beginning and the number of - // operations it cover can currently only be 1, because we support only - // entry values of a simple register location. One reason for this is that - // we currently can't calculate the size of the resulting DWARF block for - // other expressions. - return I->get() == expr_op_begin()->get() && I->getArg(0) == 1; + // The number of operations an entry value operator covers can currently + // only be 1, because we support only entry values of a simple register + // location. One reason for this is that we currently can't calculate the + // size of the resulting DWARF block for other expressions. + return I->getArg(0) == 1; } case dwarf::DW_OP_LLVM_implicit_pointer: case dwarf::DW_OP_LLVM_convert: Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -566,7 +566,6 @@ DIExpression::FragmentInfo Fragment, ValueOrMetadata *Desc); void verifyFnArgs(const DbgVariableIntrinsic &I); - void verifyNotEntryValue(const DbgVariableIntrinsic &I); /// Module-level debug info verification... void verifyCompileUnits(); @@ -4604,7 +4603,6 @@ if (auto *DII = dyn_cast(&I)) { verifyFragmentExpression(*DII); - verifyNotEntryValue(*DII); } SmallVector, 4> MDs; @@ -5701,16 +5699,6 @@ Prev, Var); } -void Verifier::verifyNotEntryValue(const DbgVariableIntrinsic &I) { - DIExpression *E = dyn_cast_or_null(I.getRawExpression()); - - // We don't know whether this intrinsic verified correctly. - if (!E || !E->isValid()) - return; - - AssertDI(!E->isEntryValue(), "Entry values are only allowed in MIR", &I); -} - void Verifier::verifyCompileUnits() { // When more than one Module is imported into the same context, such as during // an LTO build before linking the modules, ODR type uniquing may cause types Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -218,6 +218,7 @@ #include "llvm/Transforms/Utils/BreakCriticalEdges.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h" +#include "llvm/Transforms/Utils/DebugEntryValues.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/FixIrreducible.h" #include "llvm/Transforms/Utils/HelloWorld.h" Index: llvm/lib/Passes/PassBuilderPipelines.cpp =================================================================== --- llvm/lib/Passes/PassBuilderPipelines.cpp +++ llvm/lib/Passes/PassBuilderPipelines.cpp @@ -117,6 +117,7 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" +#include "llvm/Transforms/Utils/DebugEntryValues.h" #include "llvm/Transforms/Utils/InjectTLIMappings.h" #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h" #include "llvm/Transforms/Utils/Mem2Reg.h" @@ -921,6 +922,9 @@ // globals. MPM.addPass(DeadArgumentEliminationPass()); + // Mark unmodified parameters as entry values. + MPM.addPass(createModuleToFunctionPassAdaptor(DebugEntryValues())); + // Create a small function pass pipeline to cleanup after all the global // optimizations. FunctionPassManager GlobalCleanupPM; Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -249,6 +249,7 @@ FUNCTION_PASS("coro-cleanup", CoroCleanupPass()) FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass()) FUNCTION_PASS("dce", DCEPass()) +FUNCTION_PASS("dbg-entry-values", DebugEntryValues()) FUNCTION_PASS("dfa-jump-threading", DFAJumpThreadingPass()) FUNCTION_PASS("div-rem-pairs", DivRemPairsPass()) FUNCTION_PASS("dse", DSEPass()) Index: llvm/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Utils/CMakeLists.txt +++ llvm/lib/Transforms/Utils/CMakeLists.txt @@ -17,6 +17,7 @@ CodeLayout.cpp CodeMoverUtils.cpp CtorUtils.cpp + DebugEntryValues.cpp Debugify.cpp DemoteRegToStack.cpp EntryExitInstrumenter.cpp Index: llvm/lib/Transforms/Utils/DebugEntryValues.cpp =================================================================== --- /dev/null +++ llvm/lib/Transforms/Utils/DebugEntryValues.cpp @@ -0,0 +1,119 @@ +#include "llvm/Transforms/Utils/DebugEntryValues.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void llvm::markEntryValues(Function &F) { + auto SP = F.getSubprogram(); + if (!SP) { + return; + } + + auto Nodes = SP->getRetainedNodes(); + if (!Nodes) { + return; + } + + DenseMap Parameters(F.arg_size()); + std::vector FArgs(F.arg_size(), nullptr); + + for (auto it = F.arg_begin(); it != F.arg_end(); ++it) { + auto Arg = &(*it); + unsigned int idx = Arg->getArgNo(); + FArgs[idx] = cast(&(*it)); + } + + for (auto *DN : Nodes) { + if (auto *DV = dyn_cast(DN)) { + if (!DV->isParameter()) { + continue; + } + unsigned int idx = DV->getArg() - 1; + + // FIXME: arg field in DILocalVariable. + if (F.arg_size() != 0 && idx < F.arg_size()) { + Parameters.insert({DV, FArgs[idx]}); + } + } + } + + if (Parameters.size() == 0) { + return; + } + + // For modified parameters, there is a call to llvm.dbg.value + // instruction different than undef, so for those parameters we cannot use + // entry value as a backup location. + for (BasicBlock &B : F) { + for (Instruction &I : B) { + if (auto *DVI = dyn_cast(&I)) { + if (!isa(I)) { + continue; + } + + auto Var = DVI->getVariable(); + if (Var->isParameter() && !DVI->isUndef()) { + Parameters.erase(Var); + } + } + } + } + + // For unmodified parameters there is exactly one call to + // llvm.dbg.value instruction, with undef value. This is the + // situation when we can try to recover those values, so intrinsic + // is changed with an entry value expression, and variable's + // value as first operand. + for (BasicBlock &B : F) { + for (Instruction &I : B) { + if (auto *DVI = dyn_cast(&I)) { + auto Var = DVI->getVariable(); + if (!isa(I) || !Var->isParameter() || !DVI->isUndef()) { + continue; + } + auto it = Parameters.find(Var); + if (it == Parameters.end()) { + continue; + } + auto Val = Parameters[Var]; + auto MetaVal = + MetadataAsValue::get(I.getContext(), ValueAsMetadata::get(Val)); + DVI->Instruction::setOperand(0, MetaVal); + auto *DIExpr = DIExpression::get(DVI->getExpression()->getContext(), + {dwarf::DW_OP_LLVM_entry_value, 1}); + DVI->setExpression(DIExpr); + } + } + } +} + +PreservedAnalyses DebugEntryValues::run(Function &F, + FunctionAnalysisManager &AM) { + markEntryValues(F); + return PreservedAnalyses::all(); +} + +namespace { +struct DebugEntryValuesLegacyPass : public FunctionPass { + static char ID; + DebugEntryValuesLegacyPass() : FunctionPass(ID) {} + + bool runOnFunction(Function &F) override { + markEntryValues(F); + return false; + } + +}; // end of struct DebugEntryValuesLegacyPass +} // end of anonymous namespace + +char DebugEntryValuesLegacyPass::ID = 0; + +static RegisterPass + DEVCS("dbg-entry-values", + "Mark unmodified parameters' location as an entry value"); Index: llvm/lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- llvm/lib/Transforms/Utils/InlineFunction.cpp +++ llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -1740,6 +1740,31 @@ } } +// When a function inlining happens, there is no typical +// parameter passing. This situation is handled here +// by deleting calls to llvm.dbg.value instructions which +// describe the location of the variable as an entry value. +static void invalidateEntryValues(Function *Fn, Function::iterator FI) { + std::vector DbgValueToErase; + for (; FI != Fn->end(); ++FI) + for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; + ++BI) { + DbgValueInst *DVI = dyn_cast(&(*BI)); + if (!DVI) + continue; + if (DVI->getExpression()->isEntryValue()) { + UndefValue *U = UndefValue::get((&(*BI))->getType()); + (&(*BI))->replaceAllUsesWith(U); + DbgValueToErase.push_back((&(*BI))); + } + } + + for (Instruction *I : DbgValueToErase) { + I->dropAllReferences(); + I->eraseFromParent(); + } +} + /// This function inlines the called function into the basic block of the /// caller. This returns false if it is not possible to inline this call. /// The program is still in a well defined state if this occurs though. @@ -2034,6 +2059,8 @@ // instructions inlined from a function whose DISubprogram is not null. fixupLineNumbers(Caller, FirstNewBlock, &CB, CalledFunc->getSubprogram() != nullptr); + if (CalledFunc->getSubprogram() != nullptr) + invalidateEntryValues(Caller, FirstNewBlock); // Now clone the inlined noalias scope metadata. SAMetadataCloner.clone(); Index: llvm/test/Other/new-pm-defaults.ll =================================================================== --- llvm/test/Other/new-pm-defaults.ll +++ llvm/test/Other/new-pm-defaults.ll @@ -110,6 +110,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis ; CHECK-O-NEXT: Running analysis: AAManager Index: llvm/test/Other/new-pm-thinlto-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-defaults.ll +++ llvm/test/Other/new-pm-thinlto-defaults.ll @@ -79,6 +79,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-PRELINK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis ; CHECK-O-NEXT: Running analysis: AAManager Index: llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -49,6 +49,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: AAManager ; CHECK-O-NEXT: Running analysis: BasicAA Index: llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -63,6 +63,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: BlockFrequencyAnalysis on foo ; These next two can appear in any order since they are accessed as parameters Index: llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll @@ -49,6 +49,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis ; CHECK-O-NEXT: Running analysis: AAManager Index: llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll =================================================================== --- llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +++ llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll @@ -59,6 +59,7 @@ ; CHECK-O-NEXT: Running pass: GlobalOptPass ; CHECK-O-NEXT: Running pass: PromotePass ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass +; CHECK-O-NEXT: Running pass: DebugEntryValues ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: BlockFrequencyAnalysis on foo ; These next two can appear in any order since they are accessed as parameters Index: llvm/test/Transforms/DebugEntryValues/no-param-change.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DebugEntryValues/no-param-change.ll @@ -0,0 +1,63 @@ +; RUN: opt -dbg-entry-values -S < %s | FileCheck %s + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn2(i64 %0, i64 %1, i64 %2) local_unnamed_addr #0 !dbg !8 { + ; CHECK: call void @llvm.dbg.value(metadata i64 %0, metadata !13, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !17 + ; CHECK: call void @llvm.dbg.value(metadata i64 %1, metadata !14, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !17 + ; CHECK: call void @llvm.dbg.value(metadata i64 %2, metadata !15, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !17 + call void @llvm.dbg.value(metadata i64 undef, metadata !13, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i64 undef, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i64 undef, metadata !15, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata !DIArgList(i64 2, i64 undef), metadata !16, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)), !dbg !17 + tail call void @fn1(i64 5, i64 6, i64 7) #3, !dbg !18 + ret i64 0, !dbg !19 +} + +declare !dbg !20 dso_local void @fn1(i64, i64, i64) local_unnamed_addr #1 + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn3() local_unnamed_addr #0 !dbg !23 { + %1 = tail call i64 @fn2(i64 undef, i64 undef, i64 undef), !dbg !26 + ret i64 0, !dbg !27 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { noinline nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "testOriginal.c", directory: "/home/syrmia/diplomski/testF") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"uwtable", i32 1} +!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)"} +!8 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 4, type: !9, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11, !11, !11} +!11 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!12 = !{!13, !14, !15, !16} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11) +!14 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 4, type: !11) +!15 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 4, type: !11) +!16 = !DILocalVariable(name: "q", scope: !8, file: !1, line: 6, type: !11) +!17 = !DILocation(line: 0, scope: !8) +!18 = !DILocation(line: 7, column: 3, scope: !8) +!19 = !DILocation(line: 8, column: 3, scope: !8) +!20 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !21, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!21 = !DISubroutineType(types: !22) +!22 = !{null, !11, !11, !11} +!23 = distinct !DISubprogram(name: "fn3", scope: !1, file: !1, line: 12, type: !24, scopeLine: 13, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!24 = !DISubroutineType(types: !25) +!25 = !{!11} +!26 = !DILocation(line: 14, column: 10, scope: !23) +!27 = !DILocation(line: 14, column: 3, scope: !23) Index: llvm/test/Transforms/DebugEntryValues/with-param-change.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DebugEntryValues/with-param-change.ll @@ -0,0 +1,62 @@ +; RUN: opt -dbg-entry-values -S < %s | FileCheck %s + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn2(i64 %0, i64 %1, i64 %2) local_unnamed_addr #0 !dbg !8 { + ; CHECK: call void @llvm.dbg.value(metadata i64 undef, metadata !13, metadata !DIExpression()), !dbg !16 + ; CHECK: call void @llvm.dbg.value(metadata i64 undef, metadata !14, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 undef, metadata !13, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 undef, metadata !14, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 undef, metadata !15, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 2, metadata !13, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i64 3, metadata !14, metadata !DIExpression()), !dbg !16 + tail call void @fn1(i64 5, i64 6, i64 7) #3, !dbg !17 + ret i64 0, !dbg !18 +} + +declare !dbg !19 dso_local void @fn1(i64, i64, i64) local_unnamed_addr #1 + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn3() local_unnamed_addr #0 !dbg !22 { + %1 = tail call i64 @fn2(i64 undef, i64 undef, i64 undef), !dbg !25 + ret i64 0, !dbg !26 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { noinline nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "testOriginalChangedParams.c", directory: "/home/syrmia/diplomski/testF") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"uwtable", i32 1} +!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git c2574e63ff71c1d3caea48cb6200c2422bd8f33d)"} +!8 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 4, type: !9, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11, !11, !11} +!11 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!12 = !{!13, !14, !15} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11) +!14 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 4, type: !11) +!15 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 4, type: !11) +!16 = !DILocation(line: 0, scope: !8) +!17 = !DILocation(line: 8, column: 3, scope: !8) +!18 = !DILocation(line: 9, column: 3, scope: !8) +!19 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !20, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!20 = !DISubroutineType(types: !21) +!21 = !{null, !11, !11, !11} +!22 = distinct !DISubprogram(name: "fn3", scope: !1, file: !1, line: 13, type: !23, scopeLine: 14, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!23 = !DISubroutineType(types: !24) +!24 = !{!11} +!25 = !DILocation(line: 15, column: 10, scope: !22) +!26 = !DILocation(line: 15, column: 3, scope: !22) Index: llvm/test/Verifier/diexpression-entry-value-llvm-ir.ll =================================================================== --- llvm/test/Verifier/diexpression-entry-value-llvm-ir.ll +++ /dev/null @@ -1,31 +0,0 @@ -; RUN: llvm-as -disable-output <%s 2>&1| FileCheck %s - -; The DW_OP_LLVM_entry_value operation can only be used in MIR. - -; CHECK: Entry values are only allowed in MIR -; CHECK: call void @llvm.dbg.value(metadata i32 %param, metadata !{{.*}}, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)) -; CHECK: warning: ignoring invalid debug info - -define void @foo(i32 %param) !dbg !4 { -entry: - call void @llvm.dbg.value(metadata i32 %param, metadata !8, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !9 - ret void -} - -declare void @llvm.dbg.value(metadata, metadata, metadata) #0 - -attributes #0 = { nounwind readnone speculatable willreturn } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!2, !3} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) -!1 = !DIFile(filename: "a.c", directory: "/") -!2 = !{i32 2, !"Dwarf Version", i32 4} -!3 = !{i32 2, !"Debug Info Version", i32 3} -!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, type: !5, unit: !0) -!5 = !DISubroutineType(types: !6) -!6 = !{null, !7} -!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!8 = !DILocalVariable(name: "param", arg: 1, scope: !4, file: !1, type: !7) -!9 = !DILocation(line: 0, scope: !4) Index: llvm/test/Verifier/diexpression-entry-value.ll =================================================================== --- llvm/test/Verifier/diexpression-entry-value.ll +++ llvm/test/Verifier/diexpression-entry-value.ll @@ -1,12 +1,9 @@ ; RUN: not opt -S < %s 2>&1 | FileCheck %s -!named = !{!0, !1, !2} -; CHECK: invalid expression -; CHECK-NEXT: !DIExpression +!named = !{!0, !1} ; CHECK: invalid expression ; CHECK-NEXT: !DIExpression ; CHECK: invalid expression ; CHECK-NEXT: !DIExpression !0 = !DIExpression(DW_OP_LLVM_entry_value, 4, DW_OP_constu, 0, DW_OP_stack_value) -!1 = !DIExpression(DW_OP_constu, 0, DW_OP_LLVM_entry_value, 1, DW_OP_constu, 0) -!2 = !DIExpression(DW_OP_LLVM_entry_value, 100, DW_OP_constu, 0) +!1 = !DIExpression(DW_OP_LLVM_entry_value, 100, DW_OP_constu, 0)