https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/174892
>From 7aae4ff0c10b19669a9870b34cec61f76a851814 Mon Sep 17 00:00:00 2001 From: Justin Stitt <[email protected]> Date: Tue, 6 Jan 2026 15:36:33 -0800 Subject: [PATCH] [Clang] Implement inlining hints for __attribute__((warnning/error)) When functions marked with __attribute__((warning/error)) are called through inlined functions, Clang now shows the inlining chain that led to the call. The two modes are: - ``heuristic`` tries to guess which functions will be inlined to minimize the amount of source locations kept in memory and visible in LLVM IR. - ``debug`` leverages minimal debug directive tracking infrastructure to get more reliable source locations over the heuristic mode while having more compile-time overhead. ``debug`` mode is enabled when debug information ``-gline-directives-only`` (implied by ``-g1`` or higher) is available. If this debug information is not available, the ``heuristic`` mode is used which represents a best-effort approach towards accurate inline hints. When the heuristic fails and we cannot show an accurate source location for one or more hints, the source location of the initial warning is used -- completely wrong locations are never used. Fixes: https://github.com/ClangBuiltLinux/linux/issues/1571 Based-on: https://github.com/llvm/llvm-project/pull/73552 Signed-off-by: Justin Stitt <[email protected]> --- clang/docs/ReleaseNotes.rst | 8 ++ clang/include/clang/Basic/AttrDocs.td | 9 ++ .../clang/Basic/DiagnosticFrontendKinds.td | 6 + clang/lib/CodeGen/CGCall.cpp | 24 ++-- clang/lib/CodeGen/CodeGenAction.cpp | 38 ++++++ clang/test/CodeGen/attr-nomerge.cpp | 6 +- clang/test/CodeGenCXX/builtin-invoke.cpp | 4 +- .../inheriting-constructor-cleanup.cpp | 2 +- clang/test/CodeGenCXX/pfp-memcpy.cpp | 4 +- .../test/CodeGenCXX/type-aware-allocators.cpp | 2 +- .../coro-await-resume-eh.cpp | 2 +- .../backend-attribute-inlining-cross-tu.c | 67 +++++++++++ ...-attribute-inlining-debug-vs-heuristic.cpp | 92 ++++++++++++++ .../backend-attribute-inlining-modes.c | 32 +++++ .../Frontend/backend-attribute-inlining.c | 112 ++++++++++++++++++ ...ibute_parallel_for_num_threads_codegen.cpp | 8 +- ..._parallel_for_simd_num_threads_codegen.cpp | 12 +- clang/test/OpenMP/scope_codegen.cpp | 8 +- clang/test/OpenMP/single_codegen.cpp | 12 +- ...ibute_parallel_for_num_threads_codegen.cpp | 4 +- ..._parallel_for_simd_num_threads_codegen.cpp | 6 +- clang/test/OpenMP/threadprivate_codegen.cpp | 40 +++---- .../Inputs/basic-cplusplus.cpp.expected | 41 +++++-- ...plicit-template-instantiation.cpp.expected | 20 ++-- llvm/docs/LangRef.rst | 48 +++++++- llvm/include/llvm/IR/DiagnosticInfo.h | 26 +++- llvm/lib/IR/DiagnosticInfo.cpp | 37 +++++- llvm/lib/Transforms/Utils/InlineFunction.cpp | 44 +++++++ .../Inline/inlined-from-metadata.ll | 105 ++++++++++++++++ 29 files changed, 730 insertions(+), 89 deletions(-) create mode 100644 clang/test/Frontend/backend-attribute-inlining-cross-tu.c create mode 100644 clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp create mode 100644 clang/test/Frontend/backend-attribute-inlining-modes.c create mode 100644 clang/test/Frontend/backend-attribute-inlining.c create mode 100644 llvm/test/Transforms/Inline/inlined-from-metadata.ll diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 863c7392f7565..cd4795592dd6e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -291,6 +291,14 @@ Improvements to Clang's diagnostics (``-fimplicit-module-maps``). This does not affect module maps specified explicitly via ``-fmodule-map-file=``. +- ``[[gnu::warning]]`` and ``[[gnu::error]]`` diagnostics now have notes + describing inlining locations. When a function with these attributes is + called from an inlined context, Clang can now show which functions were + inlined to reach the call. When ``-gline-directives-only`` (implied by + ``-g1`` or higher) is available, accurate source locations are used; + otherwise, a heuristic fallback is used with a note suggesting how to enable + debug info for better accuracy. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 60dfdfc2f23f3..4a9f52d02ca1b 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8552,6 +8552,15 @@ pointing to precise locations of the call site in the source. dontcall(); // No Warning sizeof(dontcall()); // No Warning } + +When the call occurs through inlined functions, the inlining chain that led to +the call is shown. This helps identify which call site triggered the diagnostic +when the attributed function is called from multiple locations through inline +functions. + +The most accurate source location information for inline notes can be obtained +when ``-gline-directives-only`` (implied by ``-g1`` or higher) is enabled. +Otherwise, a heuristic approach is used to track source locations. }]; } diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 5c62bb70ebd0f..0f4ed72377775 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -94,6 +94,12 @@ def err_fe_backend_error_attr : def warn_fe_backend_warning_attr : Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo, InGroup<BackendWarningAttributes>; +def note_fe_backend_in : Note<"called by function '%0'">, BackendInfo; +def note_fe_backend_inlined : Note<"inlined by function '%0'">, BackendInfo; +def note_fe_backend_inlining_debug_info + : Note<"use '-gline-directives-only' (implied by '-g1' or higher) for " + "more accurate inlining chain locations">, + BackendInfo; def warn_toc_unsupported_type : Warning<"-mtocdata option is ignored " "for %0 because %1">, InGroup<BackendWarningAttributes>; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 04b27925bab8e..b8cf1b3d0a927 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6177,13 +6177,23 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (getDebugInfo() && TargetDecl && TargetDecl->hasAttr<MSAllocatorAttr>()) getDebugInfo()->addHeapAllocSiteMetadata(CI, RetTy->getPointeeType(), Loc); - // Add metadata if calling an __attribute__((error(""))) or warning fn. - if (TargetDecl && TargetDecl->hasAttr<ErrorAttr>()) { - llvm::ConstantInt *Line = - llvm::ConstantInt::get(Int64Ty, Loc.getRawEncoding()); - llvm::ConstantAsMetadata *MD = llvm::ConstantAsMetadata::get(Line); - llvm::MDTuple *MDT = llvm::MDNode::get(getLLVMContext(), {MD}); - CI->setMetadata("srcloc", MDT); + // Add srcloc metadata for [[gnu::error/warning]] diagnostics. Track + // inline/static calls for the heuristic fallback when debug info is not + // available. This heuristic is conservative and best-effort since static or + // inline-annotated functions are still not guaranteed to be inlined. + if (TargetDecl) { + bool NeedSrcLoc = TargetDecl->hasAttr<ErrorAttr>(); + if (!NeedSrcLoc && !getDebugInfo()) { + if (const auto *FD = dyn_cast<FunctionDecl>(TargetDecl)) + NeedSrcLoc = FD->isInlined() || FD->hasAttr<AlwaysInlineAttr>() || + FD->getStorageClass() == SC_Static || + FD->isInAnonymousNamespace(); + } + if (NeedSrcLoc) { + auto *Line = llvm::ConstantInt::get(Int64Ty, Loc.getRawEncoding()); + auto *MD = llvm::ConstantAsMetadata::get(Line); + CI->setMetadata("srcloc", llvm::MDNode::get(getLLVMContext(), {MD})); + } } // 4. Finish the call. diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 29dcabd1b0971..56e6bee7e12d6 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -732,6 +732,44 @@ void BackendConsumer::DontCallDiagHandler(const DiagnosticInfoDontCall &D) { ? diag::err_fe_backend_error_attr : diag::warn_fe_backend_warning_attr) << llvm::demangle(D.getFunctionName()) << D.getNote(); + + auto EmitNote = [&](SourceLocation Loc, StringRef FuncName, bool IsFirst) { + if (!Loc.isValid()) + Loc = LocCookie; + unsigned DiagID = + IsFirst ? diag::note_fe_backend_in : diag::note_fe_backend_inlined; + Diags.Report(Loc, DiagID) << llvm::demangle(FuncName.str()); + }; + + // Try debug info first for accurate source locations. + if (!D.getDebugInlineChain().empty()) { + SourceManager &SM = Context->getSourceManager(); + FileManager &FM = SM.getFileManager(); + for (const auto &[I, Info] : llvm::enumerate(D.getDebugInlineChain())) { + SourceLocation Loc; + if (Info.Line > 0) + if (auto FE = FM.getOptionalFileRef(Info.Filename)) + Loc = SM.translateFileLineCol(*FE, Info.Line, + Info.Column ? Info.Column : 1); + EmitNote(Loc, Info.FuncName, I == 0); + } + return; + } + + // Fall back to heuristic (srcloc metadata) when debug info is unavailable. + auto InliningDecisions = D.getInliningDecisions(); + if (InliningDecisions.empty()) + return; + + for (const auto &[I, Entry] : llvm::enumerate(InliningDecisions)) { + SourceLocation Loc = + I == 0 ? LocCookie : SourceLocation::getFromRawEncoding(Entry.second); + EmitNote(Loc, Entry.first, I == 0); + } + + // Suggest enabling debug info (at least -gline-directives-only) for more + // accurate locations. + Diags.Report(LocCookie, diag::note_fe_backend_inlining_debug_info); } void BackendConsumer::MisExpectDiagHandler( diff --git a/clang/test/CodeGen/attr-nomerge.cpp b/clang/test/CodeGen/attr-nomerge.cpp index 1cf5bb1619b31..f9c0235de89f9 100644 --- a/clang/test/CodeGen/attr-nomerge.cpp +++ b/clang/test/CodeGen/attr-nomerge.cpp @@ -92,10 +92,10 @@ void something_else_again() { // CHECK: call void @_ZN1AC1Ev({{.*}}) #[[ATTR0]] // CHECK: call void @_ZN1A1fEv({{.*}}) #[[ATTR0]] // CHECK: call void @_ZN1A1gEv({{.*}}) #[[ATTR0]] -// CHECK: call void @_ZN1A2f1Ev() #[[ATTR0]] -// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}} +// CHECK: call void @_ZN1A2f1Ev(){{.*}}#[[ATTR0]] +// CHECK: call void @_ZN1BC1Ev({{.*}}){{.*}}{{$}} // CHECK: call void @_ZN1B1gEv({{.*}}){{$}} -// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}} +// CHECK: call void @_ZN1BC1Ev({{.*}}){{.*}}{{$}} // CHECK: load ptr, ptr // CHECK: load ptr, ptr // CHECK: %[[AG:.*]] = load ptr, ptr diff --git a/clang/test/CodeGenCXX/builtin-invoke.cpp b/clang/test/CodeGenCXX/builtin-invoke.cpp index 7cc1fb1b12ea7..218b4c3c0ff2e 100644 --- a/clang/test/CodeGenCXX/builtin-invoke.cpp +++ b/clang/test/CodeGenCXX/builtin-invoke.cpp @@ -47,8 +47,8 @@ extern "C" void call_memptr(std::reference_wrapper<Callable> wrapper) { // CHECK-EMPTY: // CHECK-NEXT: memptr.virtual: // CHECK-NEXT: %vtable = load ptr, ptr %0, align 8 - // CHECK-NEXT: %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint (ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize !1 - // CHECK-NEXT: %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize !1 + // CHECK-NEXT: %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint (ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize ! + // CHECK-NEXT: %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize ! // CHECK-NEXT: br label %memptr.end // CHECK-EMPTY: // CHECK-NEXT: memptr.nonvirtual: diff --git a/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp b/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp index 722166fd86488..fc350bca36b98 100644 --- a/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp +++ b/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp @@ -37,7 +37,7 @@ void f() { // EXCEPTIONS: %[[TMP1:.*]] = alloca %struct.S1 // EXCEPTIONS: %[[TMP2:.*]] = alloca %struct.S2 // EXCEPTIONS: invoke void (ptr, ptr, ptr, ptr, ...) @_ZN4BaseC2ERK2S1RK2S2PKcz(ptr {{.*}}, ptr noundef nonnull align 1 dereferenceable(1) %[[TMP1]], ptr noundef nonnull align 1 dereferenceable(1) %[[TMP2]], ptr {{.*}}) - // EXCEPTIONS-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] + // EXCEPTIONS-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]], !srcloc // EXCEPTIONS: [[CONT]]: // EXCEPTIONS-NEXT: call void @_ZN9InheritorD1Ev(ptr {{.*}}) diff --git a/clang/test/CodeGenCXX/pfp-memcpy.cpp b/clang/test/CodeGenCXX/pfp-memcpy.cpp index be746fd8673a0..7f6fcc7af16c0 100644 --- a/clang/test/CodeGenCXX/pfp-memcpy.cpp +++ b/clang/test/CodeGenCXX/pfp-memcpy.cpp @@ -42,7 +42,7 @@ void trivial_copy(ClassWithTrivialCopy *s1) { // CHECK-NEXT: %a = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %this1, i32 0, i32 0 // CHECK-NEXT: %1 = ptrtoint ptr %this1 to i64 // CHECK-NEXT: %2 = call ptr @llvm.protected.field.ptr.p0(ptr %a, i64 %1, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.a) ] -// CHECK-NEXT: %3 = load ptr, ptr %.addr, align 8, !nonnull !1, !align !2 +// CHECK-NEXT: %3 = load ptr, ptr %.addr, align 8, !nonnull !3, !align !4 // CHECK-NEXT: %a2 = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %3, i32 0, i32 0 // CHECK-NEXT: %4 = ptrtoint ptr %3 to i64 // CHECK-NEXT: %5 = call ptr @llvm.protected.field.ptr.p0(ptr %a2, i64 %4, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.a) ] @@ -51,7 +51,7 @@ void trivial_copy(ClassWithTrivialCopy *s1) { // CHECK-NEXT: %c = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %this1, i32 0, i32 1 // CHECK-NEXT: %7 = ptrtoint ptr %this1 to i64 // CHECK-NEXT: %8 = call ptr @llvm.protected.field.ptr.p0(ptr %c, i64 %7, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.c) ] -// CHECK-NEXT: %9 = load ptr, ptr %.addr, align 8, !nonnull !1, !align !2 +// CHECK-NEXT: %9 = load ptr, ptr %.addr, align 8, !nonnull !3, !align !4 // CHECK-NEXT: %c3 = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %9, i32 0, i32 1 // CHECK-NEXT: %10 = ptrtoint ptr %9 to i64 // CHECK-NEXT: %11 = call ptr @llvm.protected.field.ptr.p0(ptr %c3, i64 %10, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.c) ] diff --git a/clang/test/CodeGenCXX/type-aware-allocators.cpp b/clang/test/CodeGenCXX/type-aware-allocators.cpp index cce9197ed0d12..a91087aa4b659 100644 --- a/clang/test/CodeGenCXX/type-aware-allocators.cpp +++ b/clang/test/CodeGenCXX/type-aware-allocators.cpp @@ -163,7 +163,7 @@ extern "C" void test_ensure_type_aware_overrides() { // CHECK: call void [[S6_DFN]]( // CHECK: [[S7_ALLOC:%.*]] = call {{.*}} @_ZN2S6nwI2S7EEPvSt13type_identityIT_EmSt11align_val_t( // CHECK: @_ZN2S7C1Ev({{.*}}[[S7_ALLOC]]) -// CHECK-NEXT: unwind label %[[S7LPAD:.*]] +// CHECK-NEXT: unwind label %[[S7LPAD:.*]], !srcloc // CHECK: [[S7_VTABLE:%vtable.*]] = load // CHECK: [[S7_DFN_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[S7_VTABLE]], i64 1 // CHECK: [[S7_DFN:%.*]] = load ptr, ptr [[S7_DFN_ADDR]] diff --git a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp index 8253337ba7390..1ad8fe0cc43ba 100644 --- a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp +++ b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp @@ -34,7 +34,7 @@ throwing_task f() { // CHECK: init.ready: // CHECK-NEXT: store i1 true, ptr %[[RESUMETHREW:.+]], align 1 // CHECK-NEXT: invoke void @_ZN18throwing_awaitable12await_resumeEv - // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]] + // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]], !srcloc // If 'await_resume' does not throw an exception, 'false' is stored in // variable RESUMETHREW. diff --git a/clang/test/Frontend/backend-attribute-inlining-cross-tu.c b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c new file mode 100644 index 0000000000000..e0f43c2f465e9 --- /dev/null +++ b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c @@ -0,0 +1,67 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: not %clang -O2 -S %t/main.c -I%t -o /dev/null 2>&1 | FileCheck %s + +// Cross-TU inlining: header functions inlined into source file. + +//--- overflow.h +[[gnu::warning("write overflow")]] +void __write_overflow(void); + +[[gnu::error("read overflow")]] +void __read_overflow(void); + +static inline void check_write(int size) { + if (size > 100) + __write_overflow(); +} + +static inline void check_read(int size) { + if (size > 50) + __read_overflow(); +} + +static inline void check_both(int size) { + check_write(size); + check_read(size); +} + +//--- main.c +#include "overflow.h" + +void test_simple_cross_tu(void) { + check_write(200); +} +// CHECK: warning: call to '__write_overflow' declared with 'warning' attribute: write overflow +// CHECK: note: called by function 'check_write' +// CHECK: main.c:{{.*}}: note: inlined by function 'test_simple_cross_tu' + +// Nested cross-TU inlining (header -> header -> source). +static inline void local_wrapper(int x) { + check_both(x); +} + +void test_nested_cross_tu(void) { + local_wrapper(200); +} +// CHECK: warning: call to '__write_overflow' declared with 'warning' attribute: write overflow +// CHECK: note: called by function 'check_write' +// CHECK: overflow.h:{{.*}}: note: inlined by function 'check_both' +// CHECK: main.c:{{.*}}: note: inlined by function 'local_wrapper' +// CHECK: main.c:{{.*}}: note: inlined by function 'test_nested_cross_tu' + +// CHECK: error: call to '__read_overflow' declared with 'error' attribute: read overflow +// CHECK: note: called by function 'check_read' +// CHECK: overflow.h:{{.*}}: note: inlined by function 'check_both' +// CHECK: main.c:{{.*}}: note: inlined by function 'local_wrapper' +// CHECK: main.c:{{.*}}: note: inlined by function 'test_nested_cross_tu' + +void test_error_cross_tu(void) { + check_read(100); +} +// CHECK: error: call to '__read_overflow' declared with 'error' attribute: read overflow +// CHECK: note: called by function 'check_read' +// CHECK: main.c:{{.*}}: note: inlined by function 'test_error_cross_tu' + +// Fallback note should appear (no debug info). +// CHECK: note: use '-gline-directives-only' (implied by '-g1' or higher) for more accurate inlining chain locations diff --git a/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp new file mode 100644 index 0000000000000..95552b61894c3 --- /dev/null +++ b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -O2 -emit-obj %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=HEURISTIC +// RUN: %clang_cc1 -O2 -emit-obj -debug-info-kind=line-directives-only %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=DEBUG + +// Verify auto-selection works between debug info and heuristic fallback. When +// we have at least -gline-directives-only we can use DILocation for accurate +// inline locations. + +// Without that debug info we fall back to a heuristic approach using srcloc +// metadata. + +[[gnu::warning("dangerous function")]] +void dangerous(); + +// Non-static, non-inline functions that get inlined at -O2. +void wrapper() { + dangerous(); +} + +void middle() { + wrapper(); +} + +void caller() { + middle(); +} + + +// HEURISTIC: :16:{{.*}}: warning: call to '{{.*}}dangerous{{.*}}' +// HEURISTIC: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}' +// HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}middle{{.*}}' +// HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}caller{{.*}}' +// HEURISTIC: note: use '-gline-directives-only' (implied by '-g1' or higher) for more accurate inlining chain locations + +// DEBUG: :16:{{.*}}: warning: call to '{{.*}}dangerous{{.*}}' +// DEBUG: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}' +// DEBUG: :20:{{.*}}: note: inlined by function '{{.*}}middle{{.*}}' +// DEBUG: :24:{{.*}}: note: inlined by function '{{.*}}caller{{.*}}' +// DEBUG-NOT: note: use '-gline-directives-only' + +// Test that functions in anonymous namespaces are properly tracked for +// inlining chain diagnostics. Anonymous namespace functions have internal +// linkage and are prime candidates for inlining. + +[[gnu::warning("do not call")]] +void bad_func(); + +namespace { +void anon_helper() { + bad_func(); +} + +void anon_middle() { + anon_helper(); +} +} // namespace + +void public_caller() { + anon_middle(); +} + +// HEURISTIC: :49:{{.*}}: warning: call to '{{.*}}bad_func{{.*}}' +// HEURISTIC: :49:{{.*}}: note: called by function '{{.*}}anon_helper{{.*}}' +// HEURISTIC: :53:{{.*}}: note: inlined by function '{{.*}}anon_middle{{.*}}' +// HEURISTIC: :58:{{.*}}: note: inlined by function '{{.*}}public_caller{{.*}}' + +// DEBUG: :49:{{.*}}: warning: call to '{{.*}}bad_func{{.*}}' +// DEBUG: :49:{{.*}}: note: called by function '{{.*}}anon_helper{{.*}}' +// DEBUG: :53:{{.*}}: note: inlined by function '{{.*}}anon_middle{{.*}}' +// DEBUG: :58:{{.*}}: note: inlined by function '{{.*}}public_caller{{.*}}' + +// always_inline forces inlining but doesn't imply +// isInlined() in the language sense. + +[[gnu::warning("always inline warning")]] +void always_inline_target(); + +__attribute__((always_inline)) +void always_inline_wrapper() { + always_inline_target(); +} + +void always_inline_caller() { + always_inline_wrapper(); +} + +// HEURISTIC: :79:{{.*}}: warning: call to '{{.*}}always_inline_target{{.*}}' +// HEURISTIC: :79:{{.*}}: note: called by function '{{.*}}always_inline_wrapper{{.*}}' +// HEURISTIC: :83:{{.*}}: note: inlined by function '{{.*}}always_inline_caller{{.*}}' + +// DEBUG: :79:{{.*}}: warning: call to '{{.*}}always_inline_target{{.*}}' +// DEBUG: :79:{{.*}}: note: called by function '{{.*}}always_inline_wrapper{{.*}}' +// DEBUG: :83:{{.*}}: note: inlined by function '{{.*}}always_inline_caller{{.*}}' diff --git a/clang/test/Frontend/backend-attribute-inlining-modes.c b/clang/test/Frontend/backend-attribute-inlining-modes.c new file mode 100644 index 0000000000000..4abc4023191f3 --- /dev/null +++ b/clang/test/Frontend/backend-attribute-inlining-modes.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -O2 -emit-obj %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ENABLED-HEURISTIC +// RUN: %clang_cc1 -O2 -emit-obj -debug-info-kind=line-directives-only %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ENABLED-DEBUG + +[[gnu::warning("do not call")]] +void bad_func(void); + +static inline void level1(void) { + bad_func(); +} + +static inline void level2(void) { + level1(); +} + +void entry(void) { + level2(); +} + +// Enabled without debug info: heuristic fallback. +// All notes point to original call site (:14). +// ENABLED-HEURISTIC: :8:{{.*}}: warning: call to 'bad_func' +// ENABLED-HEURISTIC: :8:{{.*}}: note: called by function 'level1' +// ENABLED-HEURISTIC: :12:{{.*}}: note: inlined by function 'level2' +// ENABLED-HEURISTIC: :16:{{.*}}: note: inlined by function 'entry' +// ENABLED-HEURISTIC: note: use '-gline-directives-only' (implied by '-g1' or higher) for more accurate inlining chain locations + +// Enabled with debug info: accurate locations. +// ENABLED-DEBUG: :8:{{.*}}: warning: call to 'bad_func' +// ENABLED-DEBUG: :8:{{.*}}: note: called by function 'level1' +// ENABLED-DEBUG: :12:{{.*}}: note: inlined by function 'level2' +// ENABLED-DEBUG: :16:{{.*}}: note: inlined by function 'entry' +// ENABLED-DEBUG-NOT: note: use '-gline-directives-only' diff --git a/clang/test/Frontend/backend-attribute-inlining.c b/clang/test/Frontend/backend-attribute-inlining.c new file mode 100644 index 0000000000000..1aaf98b191b90 --- /dev/null +++ b/clang/test/Frontend/backend-attribute-inlining.c @@ -0,0 +1,112 @@ +// RUN: not %clang -O2 -S %s -o /dev/null 2>&1 | FileCheck %s + +// Single-level inlining with warning attribute. +[[gnu::warning("do not call directly")]] +void __warn_single(void); + +static inline void warn_wrapper(void) { + __warn_single(); +} + +void test_single_level(void) { + warn_wrapper(); +} +// CHECK: warning: call to '__warn_single' declared with 'warning' attribute: do not call directly +// CHECK: note: called by function 'warn_wrapper' +// CHECK: :12:{{.*}}: note: inlined by function 'test_single_level' + +// Error attribute with inlining. +[[gnu::error("never call this")]] +void __error_func(void); + +static inline void error_wrapper(void) { + __error_func(); +} + +void test_error_inlined(void) { + error_wrapper(); +} +// CHECK: error: call to '__error_func' declared with 'error' attribute: never call this +// CHECK: note: called by function 'error_wrapper' +// CHECK: :27:{{.*}}: note: inlined by function 'test_error_inlined' + +// Deep nesting (5 levels). +[[gnu::warning("deep call")]] +void __warn_deep(void); + +static inline void deep1(void) { __warn_deep(); } +static inline void deep2(void) { deep1(); } +static inline void deep3(void) { deep2(); } +static inline void deep4(void) { deep3(); } +static inline void deep5(void) { deep4(); } + +void test_deep_nesting(void) { + deep5(); +} +// CHECK: warning: call to '__warn_deep' declared with 'warning' attribute: deep call +// CHECK: note: called by function 'deep1' +// CHECK: :38:{{.*}}: note: inlined by function 'deep2' +// CHECK: :39:{{.*}}: note: inlined by function 'deep3' +// CHECK: :40:{{.*}}: note: inlined by function 'deep4' +// CHECK: :41:{{.*}}: note: inlined by function 'deep5' +// CHECK: :44:{{.*}}: note: inlined by function 'test_deep_nesting' + +// Multiple call sites produce distinct diagnostics. +[[gnu::warning("deprecated")]] +void __warn_multi(void); + +static inline void multi_wrapper(void) { + __warn_multi(); +} + +void call_site_a(void) { multi_wrapper(); } +void call_site_b(void) { multi_wrapper(); } +void call_site_c(void) { multi_wrapper(); } + +// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: deprecated +// CHECK: note: called by function 'multi_wrapper' +// CHECK: :62:{{.*}}: note: inlined by function 'call_site_a' + +// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: deprecated +// CHECK: note: called by function 'multi_wrapper' +// CHECK: :63:{{.*}}: note: inlined by function 'call_site_b' + +// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: deprecated +// CHECK: note: called by function 'multi_wrapper' +// CHECK: :64:{{.*}}: note: inlined by function 'call_site_c' + +// Different nesting depths from same inner function. +[[gnu::warning("mixed depth")]] +void __warn_mixed(void); + +static inline void mixed_inner(void) { __warn_mixed(); } +static inline void mixed_middle(void) { mixed_inner(); } + +void shallow(void) { mixed_inner(); } +void deep(void) { mixed_middle(); } + +// CHECK: warning: call to '__warn_mixed' declared with 'warning' attribute: mixed depth +// CHECK: note: called by function 'mixed_inner' +// CHECK: :85:{{.*}}: note: inlined by function 'shallow' + +// CHECK: warning: call to '__warn_mixed' declared with 'warning' attribute: mixed depth +// CHECK: note: called by function 'mixed_inner' +// CHECK: :83:{{.*}}: note: inlined by function 'mixed_middle' +// CHECK: :86:{{.*}}: note: inlined by function 'deep' + +// Incidental inlining (function not marked inline/static). +// The "inlined by" note has no location since heuristic mode doesn't track it. +[[gnu::warning("incidental")]] +void __warn_incidental(void); + +void not_marked_inline(void) { __warn_incidental(); } + +void test_incidental(void) { not_marked_inline(); } + +// CHECK: warning: call to '__warn_incidental' declared with 'warning' attribute: incidental +// CHECK: note: called by function 'not_marked_inline' +// CHECK: note: inlined by function 'test_incidental' +// CHECK-NOT: :{{.*}}: note: inlined by function 'test_incidental' + +// Fallback note should appear (no debug info). +// CHECK: note: use '-gline-directives-only' (implied by '-g1' or higher) for more accurate inlining chain locations diff --git a/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp b/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp index 77e321783222b..976d72086aff2 100644 --- a/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp @@ -2508,7 +2508,7 @@ int main() { // CHECK1-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK1-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK1-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK1-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -3760,7 +3760,7 @@ int main() { // CHECK5-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK5-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK5-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK5: invoke.cont: // CHECK5-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK5-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -5012,7 +5012,7 @@ int main() { // CHECK9-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK9-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK9-NEXT: [[CALL:%.*]] = invoke noundef i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK9-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK9-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK9: invoke.cont: // CHECK9-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -6264,7 +6264,7 @@ int main() { // CHECK13-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK13-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK13-NEXT: [[CALL:%.*]] = invoke noundef i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK13-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK13-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK13: invoke.cont: // CHECK13-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK13-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 diff --git a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp index d6a3f1b8c4e3e..720c30cb9a23b 100644 --- a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp @@ -112,7 +112,7 @@ int main() { // CHECK1-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK1-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK1-NEXT: [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK1-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -1450,7 +1450,7 @@ int main() { // CHECK3-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK3-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK3-NEXT: [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK3: invoke.cont: // CHECK3-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 @@ -1787,7 +1787,7 @@ int main() { // CHECK5-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK5-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK5-NEXT: [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK5: invoke.cont: // CHECK5-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK5-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -3123,7 +3123,7 @@ int main() { // CHECK9-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK9-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK9-NEXT: [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK9-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK9-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK9: invoke.cont: // CHECK9-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK9-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -4461,7 +4461,7 @@ int main() { // CHECK11-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK11-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK11-NEXT: [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK11: invoke.cont: // CHECK11-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK11-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 @@ -4798,7 +4798,7 @@ int main() { // CHECK13-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK13-NEXT: call void @_ZN1SC1El(ptr nonnull align 8 dereferenceable(24) [[S]], i64 0) // CHECK13-NEXT: [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 dereferenceable(24) [[S]]) -// CHECK13-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK13-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK13: invoke.cont: // CHECK13-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK13-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 diff --git a/clang/test/OpenMP/scope_codegen.cpp b/clang/test/OpenMP/scope_codegen.cpp index 80b98591a675d..a3b2409aaabb9 100644 --- a/clang/test/OpenMP/scope_codegen.cpp +++ b/clang/test/OpenMP/scope_codegen.cpp @@ -185,7 +185,7 @@ int main() { // CHECK1: arrayctor.loop: // CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK1-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds nuw (i8, ptr @tc2, i64 8) @@ -267,7 +267,7 @@ int main() { // CHECK1-NEXT: [[TMP1:%.*]] = load i8, ptr [[A]], align 1 // CHECK1-NEXT: store i8 [[TMP1]], ptr [[A1]], align 1 // CHECK1-NEXT: invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[C2]], ptr noundef nonnull align 4 dereferenceable(4) @tc) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store ptr [[C2]], ptr [[TMP]], align 8 // CHECK1-NEXT: invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[TC]], ptr noundef nonnull align 4 dereferenceable(4) @tc) @@ -683,7 +683,7 @@ int main() { // CHECK4: arrayctor.loop: // CHECK4-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK4-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK4: invoke.cont: // CHECK4-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK4-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds nuw (i8, ptr @tc2, i64 8) @@ -765,7 +765,7 @@ int main() { // CHECK4-NEXT: [[TMP1:%.*]] = load i8, ptr [[A]], align 1 // CHECK4-NEXT: store i8 [[TMP1]], ptr [[A1]], align 1 // CHECK4-NEXT: invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[C2]], ptr noundef nonnull align 4 dereferenceable(4) @tc) -// CHECK4-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK4-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[TERMINATE_LPAD:%.*]], !srcloc // CHECK4: invoke.cont: // CHECK4-NEXT: store ptr [[C2]], ptr [[TMP]], align 8 // CHECK4-NEXT: invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[TC]], ptr noundef nonnull align 4 dereferenceable(4) @tc) diff --git a/clang/test/OpenMP/single_codegen.cpp b/clang/test/OpenMP/single_codegen.cpp index 0b1e158664a38..f36113e887c6d 100644 --- a/clang/test/OpenMP/single_codegen.cpp +++ b/clang/test/OpenMP/single_codegen.cpp @@ -170,7 +170,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK1: arrayctor.loop: // CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK1-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]] @@ -246,7 +246,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK1: arrayctor.loop: // CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK1-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds nuw (i8, ptr @tc2, i64 8) @@ -1048,7 +1048,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK2: arrayctor.loop: // CHECK2-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK2-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK2-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK2: invoke.cont: // CHECK2-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK2-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds nuw (i8, ptr @tc2, i64 8) @@ -1140,7 +1140,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK2: arrayctor.loop: // CHECK2-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK2-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK2-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK2: invoke.cont: // CHECK2-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK2-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]] @@ -1977,7 +1977,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK4: arrayctor.loop: // CHECK4-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK4-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK4: invoke.cont: // CHECK4-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK4-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], getelementptr inbounds nuw (i8, ptr @tc2, i64 8) @@ -2024,7 +2024,7 @@ void array_func(int n, int a[n], St s[2]) { // CHECK4: arrayctor.loop: // CHECK4-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ] // CHECK4-NEXT: invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) -// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]] +// CHECK4-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], !srcloc // CHECK4: invoke.cont: // CHECK4-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1 // CHECK4-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]] diff --git a/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp index b738321e45902..38d53c5794b69 100644 --- a/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp +++ b/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp @@ -93,7 +93,7 @@ int main() { // CHECK1-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK1-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK1-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK1-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -1380,7 +1380,7 @@ int main() { // CHECK5-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK5-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK5-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK5: invoke.cont: // CHECK5-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK5-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 diff --git a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp index 8dbf1ca9f20f9..005572b10a096 100644 --- a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp +++ b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp @@ -95,7 +95,7 @@ int main() { // CHECK1-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK1-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK1-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK1-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 @@ -1468,7 +1468,7 @@ int main() { // CHECK3-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK3-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK3-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK3: invoke.cont: // CHECK3-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 @@ -1815,7 +1815,7 @@ int main() { // CHECK5-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK5-NEXT: call void @_ZN1SC1El(ptr noundef nonnull align 8 dereferenceable(24) [[S]], i64 noundef 0) // CHECK5-NEXT: [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr noundef nonnull align 8 dereferenceable(24) [[S]]) -// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK5-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK5: invoke.cont: // CHECK5-NEXT: store i8 [[CALL]], ptr [[A]], align 1 // CHECK5-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 diff --git a/clang/test/OpenMP/threadprivate_codegen.cpp b/clang/test/OpenMP/threadprivate_codegen.cpp index d696be7b6c32f..f4028ae0944a3 100644 --- a/clang/test/OpenMP/threadprivate_codegen.cpp +++ b/clang/test/OpenMP/threadprivate_codegen.cpp @@ -1037,7 +1037,7 @@ int foobar() { // CHECK1-NEXT: store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[TMP1]], i32 noundef 1) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds [[STRUCT_S1:%.*]], ptr [[TMP1]], i64 1 // CHECK1-NEXT: store ptr [[ARRAYINIT_ELEMENT]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8 @@ -1053,7 +1053,7 @@ int foobar() { // CHECK1-NEXT: store ptr [[ARRAYINIT_ELEMENT6]], ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK1-NEXT: store ptr [[ARRAYINIT_ELEMENT6]], ptr [[ARRAYINIT_ENDOFINIT7]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYINIT_ELEMENT6]], i32 noundef 4) -// CHECK1-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]], !srcloc // CHECK1: invoke.cont9: // CHECK1-NEXT: [[ARRAYINIT_ELEMENT10:%.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[ARRAYINIT_ELEMENT6]], i64 1 // CHECK1-NEXT: store ptr [[ARRAYINIT_ELEMENT10]], ptr [[ARRAYINIT_ENDOFINIT7]], align 8 @@ -1251,7 +1251,7 @@ int foobar() { // CHECK1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -1264,7 +1264,7 @@ int foobar() { // CHECK1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// CHECK1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // CHECK1: invoke.cont7: // CHECK1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -1372,7 +1372,7 @@ int foobar() { // CHECK1-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S1:%.*]], ptr [[TMP4]], i32 0, i32 0 // CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[A]], align 4 // CHECK1-NEXT: invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP5]]) -// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK1: invoke.cont: // CHECK1-NEXT: [[TMP6:%.*]] = call i32 @__cxa_atexit(ptr @_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]] // CHECK1-NEXT: call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) #[[ATTR3]] @@ -1774,7 +1774,7 @@ int foobar() { // CHECK2-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK2-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK2: invoke.cont: // CHECK2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -1787,7 +1787,7 @@ int foobar() { // CHECK2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// CHECK2-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // CHECK2: invoke.cont7: // CHECK2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -1886,7 +1886,7 @@ int foobar() { // CHECK2-NEXT: store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK2-NEXT: store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[TMP1]], i32 noundef 1) -// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK2: invoke.cont: // CHECK2-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds [[STRUCT_S1:%.*]], ptr [[TMP1]], i64 1 // CHECK2-NEXT: store ptr [[ARRAYINIT_ELEMENT]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8 @@ -1902,7 +1902,7 @@ int foobar() { // CHECK2-NEXT: store ptr [[ARRAYINIT_ELEMENT6]], ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK2-NEXT: store ptr [[ARRAYINIT_ELEMENT6]], ptr [[ARRAYINIT_ENDOFINIT7]], align 8 // CHECK2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYINIT_ELEMENT6]], i32 noundef 4) -// CHECK2-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]], !srcloc // CHECK2: invoke.cont9: // CHECK2-NEXT: [[ARRAYINIT_ELEMENT10:%.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[ARRAYINIT_ELEMENT6]], i64 1 // CHECK2-NEXT: store ptr [[ARRAYINIT_ELEMENT10]], ptr [[ARRAYINIT_ENDOFINIT7]], align 8 @@ -2023,7 +2023,7 @@ int foobar() { // CHECK2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S1:%.*]], ptr [[TMP4]], i32 0, i32 0 // CHECK2-NEXT: [[TMP5:%.*]] = load i32, ptr [[A]], align 4 // CHECK2-NEXT: invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP5]]) -// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK2: invoke.cont: // CHECK2-NEXT: [[TMP6:%.*]] = call i32 @__cxa_atexit(ptr @_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]] // CHECK2-NEXT: call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) #[[ATTR3]] @@ -2446,7 +2446,7 @@ int foobar() { // SIMD1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // SIMD1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // SIMD1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// SIMD1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// SIMD1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // SIMD1: invoke.cont: // SIMD1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // SIMD1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -2459,7 +2459,7 @@ int foobar() { // SIMD1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // SIMD1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // SIMD1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// SIMD1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// SIMD1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // SIMD1: invoke.cont7: // SIMD1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // SIMD1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -2562,7 +2562,7 @@ int foobar() { // SIMD1: init: // SIMD1-NEXT: [[TMP2:%.*]] = load i32, ptr @_ZL3gs1, align 4 // SIMD1-NEXT: invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP2]]) -// SIMD1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// SIMD1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // SIMD1: invoke.cont: // SIMD1-NEXT: [[TMP3:%.*]] = call i32 @__cxa_atexit(ptr @_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]] // SIMD1-NEXT: call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) #[[ATTR3]] @@ -3439,7 +3439,7 @@ int foobar() { // CHECK-TLS1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK-TLS1-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK-TLS1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// CHECK-TLS1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-TLS1-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK-TLS1: invoke.cont: // CHECK-TLS1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK-TLS1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -3452,7 +3452,7 @@ int foobar() { // CHECK-TLS1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK-TLS1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK-TLS1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// CHECK-TLS1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-TLS1-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // CHECK-TLS1: invoke.cont7: // CHECK-TLS1-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK-TLS1-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -4170,7 +4170,7 @@ int foobar() { // CHECK-TLS2-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK-TLS2-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK-TLS2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// CHECK-TLS2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-TLS2-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // CHECK-TLS2: invoke.cont: // CHECK-TLS2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // CHECK-TLS2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -4183,7 +4183,7 @@ int foobar() { // CHECK-TLS2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // CHECK-TLS2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK-TLS2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// CHECK-TLS2-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// CHECK-TLS2-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // CHECK-TLS2: invoke.cont7: // CHECK-TLS2-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // CHECK-TLS2-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -5567,7 +5567,7 @@ int foobar() { // SIMD3-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8 // SIMD3-NEXT: store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // SIMD3-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) @arr_x, i32 noundef 1) -// SIMD3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// SIMD3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // SIMD3: invoke.cont: // SIMD3-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), ptr [[ARRAYINIT_ENDOFINIT1]], align 8 // SIMD3-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 4), i32 noundef 2) @@ -5580,7 +5580,7 @@ int foobar() { // SIMD3-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT]], align 8 // SIMD3-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // SIMD3-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 12), i32 noundef 4) -// SIMD3-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]] +// SIMD3-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD6:%.*]], // SIMD3: invoke.cont7: // SIMD3-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), ptr [[ARRAYINIT_ENDOFINIT5]], align 8 // SIMD3-NEXT: invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds nuw (i8, ptr @arr_x, i64 16), i32 noundef 5) @@ -5683,7 +5683,7 @@ int foobar() { // SIMD3: init: // SIMD3-NEXT: [[TMP2:%.*]] = load i32, ptr @_ZL3gs1, align 4 // SIMD3-NEXT: invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP2]]) -// SIMD3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// SIMD3-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]], !srcloc // SIMD3: invoke.cont: // SIMD3-NEXT: [[TMP3:%.*]] = call i32 @__cxa_atexit(ptr @_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]] // SIMD3-NEXT: call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) #[[ATTR3]] diff --git a/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected b/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected index cf38dfb21a7c6..90befa09691e4 100644 --- a/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected +++ b/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected @@ -83,9 +83,9 @@ int main() { // CHECK-NEXT: [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4 // CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 // CHECK-NEXT: call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1) -// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2) -// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3) -// CHECK-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0) +// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META1:![0-9]+]] +// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META2:![0-9]+]] +// CHECK-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META3:![0-9]+]] // CHECK-NEXT: store i32 [[CALL2]], ptr [[RETVAL]], align 4 // CHECK-NEXT: call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[F]]) #[[ATTR2]] // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 @@ -184,9 +184,9 @@ int main() { // MACHO-NEXT: [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4 // MACHO-NEXT: store i32 0, ptr [[RETVAL]], align 4 // MACHO-NEXT: call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1) -// MACHO-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2) -// MACHO-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3) -// MACHO-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0) +// MACHO-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META1:![0-9]+]] +// MACHO-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META2:![0-9]+]] +// MACHO-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META3:![0-9]+]] // MACHO-NEXT: store i32 [[CALL2]], ptr [[RETVAL]], align 4 // MACHO-NEXT: call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[F]]) #[[ATTR2]] // MACHO-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 @@ -239,9 +239,9 @@ int main() { // MSVC-NEXT: [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4 // MSVC-NEXT: store i32 0, ptr [[RETVAL]], align 4 // MSVC-NEXT: [[CALL:%.*]] = call noundef ptr @"??0Foo@@QEAA@H@Z"(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1) -// MSVC-NEXT: [[CALL1:%.*]] = call noundef i32 @"?function_defined_inline@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2) -// MSVC-NEXT: [[CALL2:%.*]] = call noundef i32 @"?function_defined_out_of_line@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3) -// MSVC-NEXT: [[CALL3:%.*]] = call noundef i32 @"?static_noinline_fn@@YAHH@Z"(i32 noundef 0) +// MSVC-NEXT: [[CALL1:%.*]] = call noundef i32 @"?function_defined_inline@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META5:![0-9]+]] +// MSVC-NEXT: [[CALL2:%.*]] = call noundef i32 @"?function_defined_out_of_line@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META6:![0-9]+]] +// MSVC-NEXT: [[CALL3:%.*]] = call noundef i32 @"?static_noinline_fn@@YAHH@Z"(i32 noundef 0), !srcloc [[META7:![0-9]+]] // MSVC-NEXT: store i32 [[CALL3]], ptr [[RETVAL]], align 4 // MSVC-NEXT: call void @"??1Foo@@QEAA@XZ"(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[F]]) #[[ATTR2:[0-9]+]] // MSVC-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 @@ -301,9 +301,9 @@ int main() { // MINGW-NEXT: [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4 // MINGW-NEXT: store i32 0, ptr [[RETVAL]], align 4 // MINGW-NEXT: call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1) -// MINGW-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2) -// MINGW-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3) -// MINGW-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0) +// MINGW-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META5:![0-9]+]] +// MINGW-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META6:![0-9]+]] +// MINGW-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META7:![0-9]+]] // MINGW-NEXT: store i32 [[CALL2]], ptr [[RETVAL]], align 4 // MINGW-NEXT: call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[F]]) #[[ATTR2]] // MINGW-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 @@ -348,3 +348,20 @@ int main() { // MINGW-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARG_ADDR]], align 4 // MINGW-NEXT: ret i32 [[TMP0]] // +//. +// CHECK: [[META1]] = !{i64 1048} +// CHECK: [[META2]] = !{i64 1080} +// CHECK: [[META3]] = !{i64 1122} +//. +// MACHO: [[META1]] = !{i64 1048} +// MACHO: [[META2]] = !{i64 1080} +// MACHO: [[META3]] = !{i64 1122} +//. +// MSVC: [[META5]] = !{i64 1048} +// MSVC: [[META6]] = !{i64 1080} +// MSVC: [[META7]] = !{i64 1122} +//. +// MINGW: [[META5]] = !{i64 1048} +// MINGW: [[META6]] = !{i64 1080} +// MINGW: [[META7]] = !{i64 1122} +//. diff --git a/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected b/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected index ce9ea6b84fdf3..47a02202a38f6 100644 --- a/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected +++ b/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected @@ -44,7 +44,7 @@ public: // CHECK-NEXT: store i8 [[X:%.*]], ptr [[X_ADDR]], align 1 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1 -// CHECK-NEXT: call void @_ZN3FooIcEC2Ec(ptr noundef nonnull align 1 dereferenceable(1) [[THIS1]], i8 noundef signext [[TMP0]]) +// CHECK-NEXT: call void @_ZN3FooIcEC2Ec(ptr noundef nonnull align 1 dereferenceable(1) [[THIS1]], i8 noundef signext [[TMP0]]), !srcloc [[META1:![0-9]+]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3FooIcED1Ev( @@ -52,7 +52,7 @@ public: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK-NEXT: call void @_ZN3FooIcED2Ev(ptr noundef nonnull align 1 dead_on_return(1) dereferenceable(1) [[THIS1]]) #[[ATTR1:[0-9]+]] +// CHECK-NEXT: call void @_ZN3FooIcED2Ev(ptr noundef nonnull align 1 dead_on_return(1) dereferenceable(1) [[THIS1]]) #[[ATTR1:[0-9]+]], !srcloc [[META2:![0-9]+]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3FooIcE3getEv( @@ -86,7 +86,7 @@ template struct Foo<char>; // CHECK-NEXT: store i16 [[X:%.*]], ptr [[X_ADDR]], align 2 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2 -// CHECK-NEXT: call void @_ZN3FooIsEC2Es(ptr noundef nonnull align 2 dereferenceable(2) [[THIS1]], i16 noundef signext [[TMP0]]) +// CHECK-NEXT: call void @_ZN3FooIsEC2Es(ptr noundef nonnull align 2 dereferenceable(2) [[THIS1]], i16 noundef signext [[TMP0]]), !srcloc [[META1]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3FooIsED1Ev( @@ -94,7 +94,7 @@ template struct Foo<char>; // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK-NEXT: call void @_ZN3FooIsED2Ev(ptr noundef nonnull align 2 dead_on_return(2) dereferenceable(2) [[THIS1]]) #[[ATTR1]] +// CHECK-NEXT: call void @_ZN3FooIsED2Ev(ptr noundef nonnull align 2 dead_on_return(2) dereferenceable(2) [[THIS1]]) #[[ATTR1]], !srcloc [[META2]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3FooIsE3getEv( @@ -131,7 +131,7 @@ template struct Foo<short>; // CHECK-NEXT: store i32 [[X:%.*]], ptr [[X_ADDR]], align 4 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 -// CHECK-NEXT: call void @_ZN3BarIiEC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]]) +// CHECK-NEXT: call void @_ZN3BarIiEC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]]), !srcloc [[META4:![0-9]+]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3BarIiED1Ev( @@ -139,7 +139,7 @@ template struct Foo<short>; // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK-NEXT: call void @_ZN3BarIiED2Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[THIS1]]) #[[ATTR1]] +// CHECK-NEXT: call void @_ZN3BarIiED2Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) [[THIS1]]) #[[ATTR1]], !srcloc [[META2]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3BarIiE3getEv( @@ -148,7 +148,7 @@ template struct Foo<short>; // CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], ptr [[THIS1]], i32 0, i32 0 -// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN3FooIiE3getEv(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]]) +// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN3FooIiE3getEv(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]]), !srcloc [[META5:![0-9]+]] // CHECK-NEXT: ret i32 [[CALL]] // // CHECK-LABEL: @_ZN3BarIiE3setEi( @@ -160,7 +160,7 @@ template struct Foo<short>; // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], ptr [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[_X_ADDR]], align 4 -// CHECK-NEXT: call void @_ZN3FooIiE3setEi(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]], i32 noundef [[TMP0]]) +// CHECK-NEXT: call void @_ZN3FooIiE3setEi(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]], i32 noundef [[TMP0]]), !srcloc [[META6:![0-9]+]] // CHECK-NEXT: ret void // template struct Bar<int>; @@ -176,7 +176,7 @@ template struct Bar<int>; // CHECK-NEXT: store i64 [[X:%.*]], ptr [[X_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8 -// CHECK-NEXT: call void @_ZN3BazIlEC2El(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]], i64 noundef [[TMP0]]) +// CHECK-NEXT: call void @_ZN3BazIlEC2El(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]], i64 noundef [[TMP0]]), !srcloc [[META8:![0-9]+]] // CHECK-NEXT: ret void // // CHECK-LABEL: @_ZN3BazIlED1Ev( @@ -184,7 +184,7 @@ template struct Bar<int>; // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK-NEXT: call void @_ZN3BazIlED2Ev(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]]) #[[ATTR1]] +// CHECK-NEXT: call void @_ZN3BazIlED2Ev(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]]) #[[ATTR1]], !srcloc [[META2]] // CHECK-NEXT: ret void // template struct Baz<long>; diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 8764ed51f8480..85d36812c1531 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2162,13 +2162,19 @@ For example: call of a function with this attribute is not eliminated via optimization. Front ends can provide optional ``srcloc`` metadata nodes on call sites of such callees to attach information about where in the source language such a - call came from. A string value can be provided as a note. + call came from. A string value can be provided as a note. The inliner + automatically attaches ``inlined.from`` metadata to track the chain of + inlining decisions that led to the call site; see + :ref:`inlined.from metadata <md_inlined_from>`. ``"dontcall-warn"`` This attribute denotes that a warning diagnostic should be emitted when a call of a function with this attribute is not eliminated via optimization. Front ends can provide optional ``srcloc`` metadata nodes on call sites of such callees to attach information about where in the source language such a - call came from. A string value can be provided as a note. + call came from. A string value can be provided as a note. The inliner + automatically attaches ``inlined.from`` metadata to track the chain of + inlining decisions that led to the call site; see + :ref:`inlined.from metadata <md_inlined_from>`. ``fn_ret_thunk_extern`` This attribute tells the code generator that returns from functions should be replaced with jumps to externally-defined architecture-specific symbols. @@ -7561,6 +7567,44 @@ For example, in the code below, the call instruction may only target the ... !0 = !{ptr @add, ptr @sub} +.. _md_inlined_from: + +'``inlined.from``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``inlined.from`` metadata is attached to call sites of functions with +the ``dontcall-error`` or ``dontcall-warn`` attributes by the inliner. It +records the chain of inlining decisions that led to the call surviving at +its current location, enabling front ends to emit diagnostics that show +how the call was reached through a sequence of inlining steps. + +The metadata node contains a flat list of alternating pairs: a function +name (``MDString``) followed by a source location cookie (``i64``). The +first pair identifies the function that originally contained the call and +always has a cookie of ``0`` (since the call's own ``srcloc`` metadata +already provides its location). Each subsequent pair identifies a caller +into which the previous function was inlined, with the cookie set to the +``srcloc`` value of the call site that triggered the inlining. + +.. code-block:: llvm + + ; After inlining inner() into middle() into outer(): + call void @dontcall_target(), !srcloc !0, !inlined.from !1 + ... + !0 = !{i64 42} + !1 = !{!"inner", i64 0, !"middle", i64 123, !"outer", i64 456} + +The ``srcloc`` metadata on the call provides the location cookie for the +original call site. The ``inlined.from`` entries trace outward: ``inner`` +is where the call was originally written (cookie ``0`` meaning the call's own +``srcloc`` covers it), ``middle`` inlined ``inner`` at location ``123``, and +``outer`` inlined ``middle`` at location ``456``. + +This metadata is automatically maintained by the inliner. When a function +containing a ``dontcall-error``/``dontcall-warn`` call site is inlined, the +inliner appends the caller's name and the call site's source location to the +existing ``inlined.from`` chain (creating it if it does not yet exist). + '``callback``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h index 8f6fb4da0c839..0daaa462ba715 100644 --- a/llvm/include/llvm/IR/DiagnosticInfo.h +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -1192,19 +1192,41 @@ class LLVM_ABI DiagnosticInfoSrcMgr : public DiagnosticInfo { LLVM_ABI void diagnoseDontCall(const CallInst &CI); +/// Inlining location extracted from debug info. +struct DebugInlineInfo { + StringRef FuncName; + StringRef Filename; + unsigned Line; + unsigned Column; +}; + class LLVM_ABI DiagnosticInfoDontCall : public DiagnosticInfo { StringRef CalleeName; StringRef Note; uint64_t LocCookie; + MDNode *InlinedFromMD = nullptr; + SmallVector<DebugInlineInfo, 4> DebugInlineChain; public: DiagnosticInfoDontCall(StringRef CalleeName, StringRef Note, - DiagnosticSeverity DS, uint64_t LocCookie) + DiagnosticSeverity DS, uint64_t LocCookie, + MDNode *InlinedFromMD = nullptr) : DiagnosticInfo(DK_DontCall, DS), CalleeName(CalleeName), Note(Note), - LocCookie(LocCookie) {} + LocCookie(LocCookie), InlinedFromMD(InlinedFromMD) {} + StringRef getFunctionName() const { return CalleeName; } StringRef getNote() const { return Note; } uint64_t getLocCookie() const { return LocCookie; } + MDNode *getInlinedFromMD() const { return InlinedFromMD; } + SmallVector<std::pair<StringRef, uint64_t>> getInliningDecisions() const; + + void setDebugInlineChain(SmallVector<DebugInlineInfo, 4> &&Chain) { + DebugInlineChain = std::move(Chain); + } + ArrayRef<DebugInlineInfo> getDebugInlineChain() const { + return DebugInlineChain; + } + void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_DontCall; diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index e48016fc4165f..105694d2946ac 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -484,8 +484,26 @@ void llvm::diagnoseDontCall(const CallInst &CI) { if (MDNode *MD = CI.getMetadata("srcloc")) LocCookie = mdconst::extract<ConstantInt>(MD->getOperand(0))->getZExtValue(); + MDNode *InlinedFromMD = CI.getMetadata("inlined.from"); DiagnosticInfoDontCall D(F->getName(), A.getValueAsString(), Sev, - LocCookie); + LocCookie, InlinedFromMD); + + if (const DebugLoc &DL = CI.getDebugLoc()) { + SmallVector<DebugInlineInfo, 4> DebugChain; + auto AddLocation = [&](const DILocation *Loc) { + if (auto *Scope = Loc->getScope()) + if (auto *SP = Scope->getSubprogram()) + DebugChain.push_back({SP->getName(), Loc->getFilename(), + Loc->getLine(), Loc->getColumn()}); + }; + const DILocation *Loc = DL.get(); + AddLocation(Loc); + for (const DILocation *InlinedAt = Loc->getInlinedAt(); InlinedAt; + InlinedAt = InlinedAt->getInlinedAt()) + AddLocation(InlinedAt); + D.setDebugInlineChain(std::move(DebugChain)); + } + F->getContext().diagnose(D); } } @@ -500,3 +518,20 @@ void DiagnosticInfoDontCall::print(DiagnosticPrinter &DP) const { if (!getNote().empty()) DP << ": " << getNote(); } + +SmallVector<std::pair<StringRef, uint64_t>> +DiagnosticInfoDontCall::getInliningDecisions() const { + SmallVector<std::pair<StringRef, uint64_t>> Chain; + if (!InlinedFromMD) + return Chain; + + for (unsigned I = 0, E = InlinedFromMD->getNumOperands(); I + 1 < E; I += 2) { + auto *NameMD = dyn_cast<MDString>(InlinedFromMD->getOperand(I)); + auto *LocMD = + mdconst::dyn_extract<ConstantInt>(InlinedFromMD->getOperand(I + 1)); + if (NameMD && !NameMD->getString().empty()) + Chain.emplace_back(NameMD->getString(), + LocMD ? LocMD->getZExtValue() : 0); + } + return Chain; +} diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index 3230b306f17d1..ee18b08951959 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -974,6 +974,46 @@ static void PropagateCallSiteMetadata(CallBase &CB, Function::iterator FStart, } } +/// Track inlining chain via inlined.from metadata for dontcall diagnostics. +static void PropagateInlinedFromMetadata(CallBase &CB, StringRef CalledFuncName, + StringRef CallerFuncName, + Function::iterator FStart, + Function::iterator FEnd) { + LLVMContext &Ctx = CB.getContext(); + uint64_t InlineSiteLoc = 0; + if (auto *MD = CB.getMetadata("srcloc")) + if (auto *CI = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0))) + InlineSiteLoc = CI->getZExtValue(); + + auto *I64Ty = Type::getInt64Ty(Ctx); + auto MakeMDInt = [&](uint64_t V) { + return ConstantAsMetadata::get(ConstantInt::get(I64Ty, V)); + }; + + for (BasicBlock &BB : make_range(FStart, FEnd)) { + for (Instruction &I : BB) { + auto *CI = dyn_cast<CallInst>(&I); + if (!CI || !CI->getMetadata("srcloc")) + continue; + auto *Callee = CI->getCalledFunction(); + if (!Callee || (!Callee->hasFnAttribute("dontcall-error") && + !Callee->hasFnAttribute("dontcall-warn"))) + continue; + + SmallVector<Metadata *, 8> Ops; + if (MDNode *Existing = CI->getMetadata("inlined.from")) + append_range(Ops, Existing->operands()); + else { + Ops.push_back(MDString::get(Ctx, CalledFuncName)); + Ops.push_back(MakeMDInt(0)); + } + Ops.push_back(MDString::get(Ctx, CallerFuncName)); + Ops.push_back(MakeMDInt(InlineSiteLoc)); + CI->setMetadata("inlined.from", MDNode::get(Ctx, Ops)); + } + } +} + /// Bundle operands of the inlined function must be added to inlined call sites. static void PropagateOperandBundles(Function::iterator InlinedBB, Instruction *CallSiteEHPad) { @@ -2849,6 +2889,10 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI, } } + // Propagate inlined.from metadata for dontcall diagnostics. + PropagateInlinedFromMetadata(CB, CalledFunc->getName(), Caller->getName(), + FirstNewBlock, Caller->end()); + // Register any cloned assumptions. if (IFI.GetAssumptionCache) for (BasicBlock &NewBlock : diff --git a/llvm/test/Transforms/Inline/inlined-from-metadata.ll b/llvm/test/Transforms/Inline/inlined-from-metadata.ll new file mode 100644 index 0000000000000..f067dc4249bb9 --- /dev/null +++ b/llvm/test/Transforms/Inline/inlined-from-metadata.ll @@ -0,0 +1,105 @@ +; RUN: opt < %s -passes=inline -S | FileCheck %s + +; Verify that the inliner propagates !inlined.from metadata on call sites +; targeting functions with dontcall attributes. + +declare void @dontcall_err() "dontcall-error"="error msg" +declare void @dontcall_warn() "dontcall-warn"="warning msg" + +define internal void @inner_err() { + call void @dontcall_err(), !srcloc !0 + ret void +} + +define void @test_single_level() { + call void @inner_err(), !srcloc !1 + ret void +} + +; CHECK-LABEL: define void @test_single_level() +; CHECK: call void @dontcall_err(), !srcloc [[SRCLOC_SINGLE:![0-9]+]], !inlined.from [[SINGLE:![0-9]+]] +; CHECK-NOT: call void @inner_err + +define internal void @inner_warn() { + call void @dontcall_warn(), !srcloc !2 + ret void +} + +define internal void @middle_warn() { + call void @inner_warn(), !srcloc !3 + ret void +} + +define void @test_two_levels() { + call void @middle_warn(), !srcloc !4 + ret void +} + +; CHECK-LABEL: define void @test_two_levels() +; CHECK: call void @dontcall_warn(), !srcloc [[SRCLOC_TWO:![0-9]+]], !inlined.from [[TWO:![0-9]+]] +; CHECK-NOT: call void @inner_warn +; CHECK-NOT: call void @middle_warn + +define internal void @multi_calls() { + call void @dontcall_err(), !srcloc !5 + call void @dontcall_warn(), !srcloc !6 + ret void +} + +define void @test_multi_calls() { + call void @multi_calls(), !srcloc !7 + ret void +} + +; CHECK-LABEL: define void @test_multi_calls() +; CHECK: call void @dontcall_err(), !srcloc {{![0-9]+}}, !inlined.from [[MULTI:![0-9]+]] +; CHECK: call void @dontcall_warn(), !srcloc {{![0-9]+}}, !inlined.from [[MULTI]] +; CHECK-NOT: call void @multi_calls + +declare void @regular_func() + +define internal void @has_regular_call() { + call void @regular_func(), !srcloc !8 + ret void +} + +define void @test_no_metadata_on_regular() { + call void @has_regular_call(), !srcloc !9 + ret void +} + +; CHECK-LABEL: define void @test_no_metadata_on_regular() +; CHECK: call void @regular_func() +; CHECK-NOT: !inlined.from + +define internal void @no_srcloc_inner() { + call void @dontcall_err() + ret void +} + +define void @test_no_srcloc() { + call void @no_srcloc_inner(), !srcloc !10 + ret void +} + +; CHECK-LABEL: define void @test_no_srcloc() +; CHECK: call void @dontcall_err() +; CHECK-NOT: !inlined.from + +!0 = !{i64 100} +!1 = !{i64 200} +!2 = !{i64 300} +!3 = !{i64 400} +!4 = !{i64 500} +!5 = !{i64 600} +!6 = !{i64 700} +!7 = !{i64 800} +!8 = !{i64 900} +!9 = !{i64 1000} +!10 = !{i64 1100} + +; CHECK-DAG: [[SRCLOC_SINGLE]] = !{i64 100} +; CHECK-DAG: [[SINGLE]] = !{!"inner_err", i64 0, !"test_single_level", i64 200} +; CHECK-DAG: [[SRCLOC_TWO]] = !{i64 300} +; CHECK-DAG: [[TWO]] = !{!"inner_warn", i64 0, !"middle_warn", i64 400, !"test_two_levels", i64 500} +; CHECK-DAG: [[MULTI]] = !{!"multi_calls", i64 0, !"test_multi_calls", i64 800} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
