https://github.com/jryans updated 
https://github.com/llvm/llvm-project/pull/189969

>From 20b5e4c3a015bfef0f9f0b797c866b7d1fbbbb26 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Wed, 1 Apr 2026 15:09:06 +0100
Subject: [PATCH 1/8] [clang][DebugInfo] Add inlined subprogram metadata for
 compiler built-ins

This wraps compiler built-ins in an artificial inlined subprogram for
debug info purposes. This makes compiler built-in usage legible to debug
info consumers like profilers, which can then annotate time spent with
the built-in function name. For example, calls to e.g.
`__builtin_alloca` and `__builtin_memset` become visible to profilers
and debuggers, improving the correspondence to the source program.
---
 clang/lib/CodeGen/CGBuiltin.cpp        |  5 +++++
 clang/lib/CodeGen/CGDebugInfo.cpp      | 22 ++++++++++++++++++++++
 clang/lib/CodeGen/CGDebugInfo.h        | 16 ++++++++++++++++
 clang/test/DebugInfo/Generic/builtin.c | 26 ++++++++++++++++++++++++++
 4 files changed, 69 insertions(+)
 create mode 100644 clang/test/DebugInfo/Generic/builtin.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 453db290243d2..3667e89aad6b2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2705,6 +2705,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
   assert(!getContext().BuiltinInfo.isImmediate(BuiltinID) &&
          "Should not codegen for consteval builtins");
 
+  // Treat built-in as call to artificial inlined function in debug info.
+  // This enables e.g. profiling tools to annotate time spent in user-called
+  // built-ins with the built-in function name.
+  ApplyBuiltinDebugLocation DebugScope(*this, GD);
+
   const FunctionDecl *FD = GD.getDecl()->getAsFunction();
   // See if we can constant fold this builtin.  If so, don't emit it at all.
   // TODO: Extend this handling to all builtin calls that we can constant-fold.
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index cdebf4ce232ea..3baff7517d5fc 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -347,6 +347,19 @@ ApplyInlineDebugLocation::~ApplyInlineDebugLocation() {
   DI.EmitLocation(CGF->Builder, SavedLocation);
 }
 
+static llvm::DILocation *createBuiltinInlineAt(CodeGenFunction &CGF,
+                                               GlobalDecl GD) {
+  if (!CGF.getDebugInfo()) {
+    return nullptr;
+  }
+  auto &DI = *CGF.getDebugInfo();
+  return DI.createBuiltinFunctionLocation(CGF.Builder, GD);
+}
+
+ApplyBuiltinDebugLocation::ApplyBuiltinDebugLocation(CodeGenFunction &CGF,
+                                                     GlobalDecl BuiltinFn)
+    : Apply(CGF, createBuiltinInlineAt(CGF, BuiltinFn)) {}
+
 void CGDebugInfo::setLocation(SourceLocation Loc) {
   // If the new location isn't valid return.
   if (Loc.isInvalid())
@@ -5134,6 +5147,15 @@ void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy 
&Builder) {
   setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
 }
 
+llvm::DILocation *
+CGDebugInfo::createBuiltinFunctionLocation(CGBuilderTy &Builder,
+                                           GlobalDecl GD) {
+  const auto *FD = cast<FunctionDecl>(GD.getDecl());
+  const auto Location = Builder.getCurrentDebugLocation();
+  return CreateSyntheticInlineAt(Location, getFunctionName(FD),
+                                 Location->getFile());
+}
+
 void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
   // Update our current location
   setLocation(Loc);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 0922c629afc46..c59495ebc6209 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -503,6 +503,10 @@ class CGDebugInfo {
   /// End an inlined function scope.
   void EmitInlineFunctionEnd(CGBuilderTy &Builder);
 
+  /// Create location for an inlined built-in function.
+  llvm::DILocation *createBuiltinFunctionLocation(CGBuilderTy &Builder,
+                                                  GlobalDecl GD);
+
   /// Emit debug info for a function declaration.
   /// \p Fn is set only when a declaration for a debug call site gets created.
   void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
@@ -999,6 +1003,18 @@ class ApplyInlineDebugLocation {
   ApplyInlineDebugLocation &operator=(ApplyInlineDebugLocation &) = delete;
 };
 
+/// A scoped helper to set the current debug location to a inlined location for
+/// a built-in function. The function is marked as artificial in debug info to
+/// convey the built-in aspect.
+class ApplyBuiltinDebugLocation {
+  ApplyDebugLocation Apply;
+
+public:
+  ApplyBuiltinDebugLocation(CodeGenFunction &CGF, GlobalDecl BuiltinFn);
+  ApplyBuiltinDebugLocation(const ApplyBuiltinDebugLocation &) = delete;
+  ApplyBuiltinDebugLocation &operator=(ApplyBuiltinDebugLocation &) = delete;
+};
+
 class SanitizerDebugLocation {
   CodeGenFunction *CGF;
   ApplyDebugLocation Apply;
diff --git a/clang/test/DebugInfo/Generic/builtin.c 
b/clang/test/DebugInfo/Generic/builtin.c
new file mode 100644
index 0000000000000..396b8024e8566
--- /dev/null
+++ b/clang/test/DebugInfo/Generic/builtin.c
@@ -0,0 +1,26 @@
+
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -debug-info-kind=limited 
-emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+void fun() {
+    // CHECK: %0 = alloca i8, i64 4{{.*}}, !dbg [[B1:!.*]]
+    void *a = __builtin_alloca(4);
+
+    // CHECK: %1 = alloca i8, i64 4{{.*}}, !dbg [[B2:!.*]]
+    // Ensure calling same built-in twice only produces one `DISubprogram` 
entry
+    void *b = __builtin_alloca(4);
+
+    // CHECK: call void @llvm.memset{{.*}}, !dbg [[B3:!.*]]
+    __builtin_memset(a, 0, 4);
+}
+
+// CHECK: [[B1]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I1:!.*]])
+// CHECK: [[S1]] = distinct !DISubprogram(name: "__builtin_alloca"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I1]] = !DILocation(line: 6,
+
+// Second call should reuse same `DISubprogram` scope
+// CHECK: [[B2]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I2:!.*]])
+// CHECK: [[I2]] = !DILocation(line: 10,
+
+// CHECK: [[B3]] = !DILocation(line: 0, scope: [[S3:!.*]], inlinedAt: 
[[I3:!.*]])
+// CHECK: [[S3]] = distinct !DISubprogram(name: "__builtin_memset"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I3]] = !DILocation(line: 13,

>From 65c86634efb1c7f1c0883e9718b1cc67dd5a2a1e Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Wed, 8 Apr 2026 15:03:55 +0100
Subject: [PATCH 2/8] Exclude various non-call-like built-ins

Several categories of built-ins should not be part of the artificial
inlined function debug info treatment:

- target-specific built-ins
- library functions emitted as direct calls
- optimisation hint built-ins
- trap and exception built-ins
- annotation built-ins
---
 clang/lib/CodeGen/CGBuiltin.cpp        | 73 +++++++++++++++++++++++++-
 clang/lib/CodeGen/CGDebugInfo.h        |  2 -
 clang/test/DebugInfo/Generic/builtin.c | 35 ++++++++++--
 3 files changed, 102 insertions(+), 8 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 3667e89aad6b2..94f6344249851 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2699,6 +2699,65 @@ RValue CodeGenFunction::emitStdcFirstBit(const CallExpr 
*E, Intrinsic::ID IntID,
   return RValue::get(Result);
 }
 
+/// Determines whether we should treat a given built-in as a call to an
+/// artificial inlined function in debug info.
+static bool shouldUseBuiltinDebugLocation(unsigned BuiltinID) {
+  switch (BuiltinID) {
+  case Builtin::BI__builtin_unpredictable:
+  case Builtin::BI__builtin_expect:
+  case Builtin::BI__builtin_expect_with_probability:
+  case Builtin::BI__builtin_assume_aligned:
+  case Builtin::BI__builtin_assume_dereferenceable:
+  case Builtin::BI__assume:
+  case Builtin::BI__builtin_assume:
+  case Builtin::BI__builtin_assume_separate_storage:
+  case Builtin::BI__builtin_allow_runtime_check:
+  case Builtin::BI__builtin_allow_sanitize_check:
+  case Builtin::BI__builtin_constant_p:
+  case Builtin::BI__builtin_prefetch:
+  case Builtin::BI__builtin___clear_cache:
+  case Builtin::BI__builtin_unreachable: {
+    // Exclude optimisation hint built-ins. These are a form of communicating
+    // additional constraints to the compiler.
+    return false;
+  }
+  case Builtin::BI__builtin_trap:
+  case Builtin::BI__builtin_verbose_trap:
+  case Builtin::BI__debugbreak:
+  case Builtin::BI__builtin_eh_return:
+  case Builtin::BI__builtin_unwind_init:
+  case Builtin::BI__exception_code:
+  case Builtin::BI_exception_code:
+  case Builtin::BI__exception_info:
+  case Builtin::BI_exception_info:
+  case Builtin::BI__abnormal_termination:
+  case Builtin::BI_abnormal_termination: {
+    // Exclude trap and exception built-ins. These may use their own debug
+    // location handling, so we avoid making debug changes so they may inspect
+    // the caller as-is without additional debug info layers.
+    return false;
+  }
+  case Builtin::BI__annotation:
+  case Builtin::BI__builtin_annotation: {
+    // Exclude annotation built-ins. These attach debug-time information.
+    return false;
+  }
+  case Builtin::BI__builtin_operator_new:
+  case Builtin::BI__builtin_operator_delete: {
+    // Exclude C++ operator built-ins. These are emitted as normal calls.
+    return false;
+  }
+  }
+
+  // Most generic (non-target-specific) built-ins are call-like, so we default
+  // to enabling this debug info treatment.
+  return true;
+
+  // See also further exclusions of library functions emitted as normal calls
+  // and target-specific built-ins towards the end of `EmitBuiltinExpr` which
+  // overrides the value returned here.
+}
+
 RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned 
BuiltinID,
                                         const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -2708,7 +2767,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
   // Treat built-in as call to artificial inlined function in debug info.
   // This enables e.g. profiling tools to annotate time spent in user-called
   // built-ins with the built-in function name.
-  ApplyBuiltinDebugLocation DebugScope(*this, GD);
+  // See `useBuiltinDebugLocation` for cases where this treatment is disabled.
+  auto DebugScope =
+      shouldUseBuiltinDebugLocation(BuiltinID)
+          ? std::make_optional<ApplyBuiltinDebugLocation>(*this, GD)
+          : std::nullopt;
 
   const FunctionDecl *FD = GD.getDecl()->getAsFunction();
   // See if we can constant fold this builtin.  If so, don't emit it at all.
@@ -6641,6 +6704,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
   }
   }
 
+  // All cases beyond this point are excluded from the artificial inlined
+  // function in debug info treatment:
+  // - library functions handled below are emitted as normal calls, so an
+  //   inlined wrapper of the same function is redundant
+  // - target-specific built-ins are mainly assembly-like concepts, so they
+  //   should not be recorded in debug info as if they were calls
+  DebugScope = std::nullopt;
+
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
   // the call using the normal call path, but using the unmangled
   // version of the function name.
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index c59495ebc6209..af92273020963 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -1011,8 +1011,6 @@ class ApplyBuiltinDebugLocation {
 
 public:
   ApplyBuiltinDebugLocation(CodeGenFunction &CGF, GlobalDecl BuiltinFn);
-  ApplyBuiltinDebugLocation(const ApplyBuiltinDebugLocation &) = delete;
-  ApplyBuiltinDebugLocation &operator=(ApplyBuiltinDebugLocation &) = delete;
 };
 
 class SanitizerDebugLocation {
diff --git a/clang/test/DebugInfo/Generic/builtin.c 
b/clang/test/DebugInfo/Generic/builtin.c
index 396b8024e8566..f6aa94de53f21 100644
--- a/clang/test/DebugInfo/Generic/builtin.c
+++ b/clang/test/DebugInfo/Generic/builtin.c
@@ -2,25 +2,50 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu %s -debug-info-kind=limited 
-emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
 void fun() {
+    // Most call-like built-ins are wrapped in an artificial inlined function 
in
+    // debug info, making them visible to e.g. profiling tools.
     // CHECK: %0 = alloca i8, i64 4{{.*}}, !dbg [[B1:!.*]]
     void *a = __builtin_alloca(4);
 
+    // Ensure calling same built-in only produces one `DISubprogram` entry.
     // CHECK: %1 = alloca i8, i64 4{{.*}}, !dbg [[B2:!.*]]
-    // Ensure calling same built-in twice only produces one `DISubprogram` 
entry
     void *b = __builtin_alloca(4);
 
     // CHECK: call void @llvm.memset{{.*}}, !dbg [[B3:!.*]]
     __builtin_memset(a, 0, 4);
+
+    // Ensure certain built-ins like optimisation hints are excluded.
+    // CHECK: call void @llvm.assume{{.*}}, !dbg [[B4:!.*]]
+    __builtin_assume(a != 0);
+
+    // Ensure target-specific built-ins are excluded.
+    // CHECK: call i64 @llvm.x86.rdtsc(), !dbg [[B5:!.*]]
+    __builtin_ia32_rdtsc();
+
+    // Ensure library functions emitted as normal calls are excluded.
+    // CHECK: call ptr @malloc{{.*}}, !dbg [[B6:!.*]]
+    void *c = __builtin_malloc(4);
 }
 
 // CHECK: [[B1]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I1:!.*]])
 // CHECK: [[S1]] = distinct !DISubprogram(name: "__builtin_alloca"{{.*}}, 
flags: DIFlagArtificial
-// CHECK: [[I1]] = !DILocation(line: 6,
+// CHECK: [[I1]] = !DILocation(line: 8,
 
-// Second call should reuse same `DISubprogram` scope
+// Second call should reuse same `DISubprogram` scope.
 // CHECK: [[B2]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I2:!.*]])
-// CHECK: [[I2]] = !DILocation(line: 10,
+// CHECK: [[I2]] = !DILocation(line: 12,
 
 // CHECK: [[B3]] = !DILocation(line: 0, scope: [[S3:!.*]], inlinedAt: 
[[I3:!.*]])
 // CHECK: [[S3]] = distinct !DISubprogram(name: "__builtin_memset"{{.*}}, 
flags: DIFlagArtificial
-// CHECK: [[I3]] = !DILocation(line: 13,
+// CHECK: [[I3]] = !DILocation(line: 15,
+
+// Excluded built-ins should use location without inlined function wrapper.
+
+// CHECK: [[B4]] = !DILocation(line: 19,
+// CHECK-NOT: distinct !DISubprogram(name: "__builtin_assume"{{.*}}, flags: 
DIFlagArtificial
+
+// CHECK: [[B5]] = !DILocation(line: 23,
+// CHECK-NOT: distinct !DISubprogram(name: "__builtin_ia32_rdtsc"{{.*}}, 
flags: DIFlagArtificial
+
+// CHECK: [[B6]] = !DILocation(line: 27,
+// CHECK-NOT: distinct !DISubprogram(name: "__builtin_malloc"{{.*}}, flags: 
DIFlagArtificial

>From 1346aea036249a1e333b44742cb6b0067a9e0d8e Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Wed, 1 Apr 2026 15:26:16 +0100
Subject: [PATCH 3/8] Adjust test KeyInstructions/builtin.c for inlined
 compiler built-ins

---
 .../test/DebugInfo/KeyInstructions/builtin.c  | 102 +++++++++++-------
 1 file changed, 65 insertions(+), 37 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/builtin.c 
b/clang/test/DebugInfo/KeyInstructions/builtin.c
index ce8c6124fe923..c7f63ff8420df 100644
--- a/clang/test/DebugInfo/KeyInstructions/builtin.c
+++ b/clang/test/DebugInfo/KeyInstructions/builtin.c
@@ -13,78 +13,106 @@ int v = 3;
 
 void fun() {
 // CHECK: %a = alloca ptr, align 8
-// CHECK: %0 = alloca i8, i64 4{{.*}}, !dbg [[G1R2:!.*]]
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G1R1:!.*]], !annotation
+// CHECK: %0 = alloca i8, i64 4{{.*}}, !dbg [[B1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B1:!.*]], !annotation
 // CHECK: store ptr %0, ptr %a{{.*}}, !dbg [[G1R1:!.*]]
     void *a = __builtin_alloca(4);
 
-// CHECK: %1 = alloca i8, i64 4{{.*}}, !dbg [[G2R2:!.*]]
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G2R1:!.*]], !annotation
+// CHECK: %1 = alloca i8, i64 4{{.*}}, !dbg [[B2:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B2:!.*]], !annotation
 // CHECK: store ptr %1, ptr %b{{.*}}, !dbg [[G2R1:!.*]]
     void *b = __builtin_alloca_with_align(4, 8);
 
 // CHECK: %2 = load <4 x float>, ptr @mat{{.*}}, !dbg [[G3R2:!.*]]
-// CHECK: call void @llvm.matrix.column.major.store.v4f32{{.*}}, !dbg 
[[G3R1:!.*]]
+// CHECK: call void @llvm.matrix.column.major.store.v4f32{{.*}}, !dbg 
[[B3:!.*]]
     __builtin_matrix_column_major_store(mat, f4, sizeof(float) * 2);
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B4:!.*]]
     __builtin_bzero(f4, sizeof(float) * 2);
 
-// CHECK: call void @llvm.memmove{{.*}}, !dbg [[G5R1:!.*]]
+// CHECK: call void @llvm.memmove{{.*}}, !dbg [[B5:!.*]]
     __builtin_bcopy(f4, f8, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G6R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[B6:!.*]]
     __builtin_memcpy(f4, f8, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G7R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[B7:!.*]]
     __builtin_mempcpy(f4, f8, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G8R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[B8:!.*]]
     __builtin_memcpy_inline(f4, f8, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G9R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[B9:!.*]]
     __builtin___memcpy_chk(f4, f8, sizeof(float) * 4, -1);
 
-// CHECK: call void @llvm.memmove{{.*}}, !dbg [[G10R1:!.*]]
+// CHECK: call void @llvm.memmove{{.*}}, !dbg [[B10:!.*]]
     __builtin___memmove_chk(f4, f8, sizeof(float) * 4, -1);
 
-// CHECK: call void @llvm.memmove{{.*}}, !dbg [[G11R1:!.*]]
+// CHECK: call void @llvm.memmove{{.*}}, !dbg [[B11:!.*]]
     __builtin_memmove(f4, f8, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G12R1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B12:!.*]]
     __builtin_memset(f4, 0, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G13R1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B13:!.*]]
     __builtin_memset_inline(f4, 0, sizeof(float) * 4);
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G14R1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[B14:!.*]]
     __builtin___memset_chk(f4, 0, sizeof(float), -1);
 
-// CHECK: %3 = load i32, ptr @v{{.*}}, !dbg [[G15R3:!.*]]
-// CHECK-NEXT: %4 = trunc i32 %3 to i8, !dbg [[G15R2:!.*]]
-// CHECK-NEXT: call void @llvm.memset{{.*}}, !dbg [[G15R1:!.*]]
+// CHECK: %3 = load i32, ptr @v{{.*}}, !dbg [[G4R3:!.*]]
+// CHECK-NEXT: %4 = trunc i32 %3 to i8, !dbg [[B15:!.*]]
+// CHECK-NEXT: call void @llvm.memset{{.*}}, !dbg [[B15:!.*]]
     __builtin_memset(f4, v, sizeof(float) * 4);
-// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
+// CHECK: ret{{.*}}, !dbg [[G5R1:!.*]]
 }
 
-// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[B1]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I1:!.*]])
+// CHECK: [[S1]] = distinct !DISubprogram(name: "__builtin_alloca"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I1]] = !DILocation(line: 19,
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
-// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[B2]] = !DILocation(line: 0, scope: [[S2:!.*]], inlinedAt: 
[[I2:!.*]])
+// CHECK: [[S2]] = distinct !DISubprogram(name: 
"__builtin_alloca_with_align"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I2]] = !DILocation(line: 24,
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
 // CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
-// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
-// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[B3]] = !DILocation(line: 0, scope: [[S3:!.*]], inlinedAt: 
[[I3:!.*]])
+// CHECK: [[S3]] = distinct !DISubprogram(name: 
"__builtin_matrix_column_major_store"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I3]] = !DILocation(line: 28,
+// CHECK: [[B4]] = !DILocation(line: 0, scope: [[S4:!.*]], inlinedAt: 
[[I4:!.*]])
+// CHECK: [[S4]] = distinct !DISubprogram(name: "__builtin_bzero"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I4]] = !DILocation(line: 31,
+// CHECK: [[B5]] = !DILocation(line: 0, scope: [[S5:!.*]], inlinedAt: 
[[I5:!.*]])
+// CHECK: [[S5]] = distinct !DISubprogram(name: "__builtin_bcopy"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I5]] = !DILocation(line: 34,
+// CHECK: [[B6]] = !DILocation(line: 0, scope: [[S6:!.*]], inlinedAt: 
[[I6:!.*]])
+// CHECK: [[S6]] = distinct !DISubprogram(name: "__builtin_memcpy"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I6]] = !DILocation(line: 37,
+// CHECK: [[B7]] = !DILocation(line: 0, scope: [[S7:!.*]], inlinedAt: 
[[I7:!.*]])
+// CHECK: [[S7]] = distinct !DISubprogram(name: "__builtin_mempcpy"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I7]] = !DILocation(line: 40,
+// CHECK: [[B8]] = !DILocation(line: 0, scope: [[S8:!.*]], inlinedAt: 
[[I8:!.*]])
+// CHECK: [[S8]] = distinct !DISubprogram(name: 
"__builtin_memcpy_inline"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I8]] = !DILocation(line: 43,
+// CHECK: [[B9]] = !DILocation(line: 0, scope: [[S9:!.*]], inlinedAt: 
[[I9:!.*]])
+// CHECK: [[S9]] = distinct !DISubprogram(name: 
"__builtin___memcpy_chk"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I9]] = !DILocation(line: 46,
+// CHECK: [[B10]] = !DILocation(line: 0, scope: [[S10:!.*]], inlinedAt: 
[[I10:!.*]])
+// CHECK: [[S10]] = distinct !DISubprogram(name: 
"__builtin___memmove_chk"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I10]] = !DILocation(line: 49,
+// CHECK: [[B11]] = !DILocation(line: 0, scope: [[S11:!.*]], inlinedAt: 
[[I11:!.*]])
+// CHECK: [[S11]] = distinct !DISubprogram(name: "__builtin_memmove"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I11]] = !DILocation(line: 52,
+// CHECK: [[B12]] = !DILocation(line: 0, scope: [[S12:!.*]], inlinedAt: 
[[I12:!.*]])
+// CHECK: [[S12]] = distinct !DISubprogram(name: "__builtin_memset"{{.*}}, 
flags: DIFlagArtificial
+// CHECK: [[I12]] = !DILocation(line: 55,
+// CHECK: [[B13]] = !DILocation(line: 0, scope: [[S13:!.*]], inlinedAt: 
[[I13:!.*]])
+// CHECK: [[S13]] = distinct !DISubprogram(name: 
"__builtin_memset_inline"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I13]] = !DILocation(line: 58,
+// CHECK: [[B14]] = !DILocation(line: 0, scope: [[S14:!.*]], inlinedAt: 
[[I14:!.*]])
+// CHECK: [[S14]] = distinct !DISubprogram(name: 
"__builtin___memset_chk"{{.*}}, flags: DIFlagArtificial
+// CHECK: [[I14]] = !DILocation(line: 61,
+// CHECK: [[G4R3]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 3)
+// CHECK: [[B15]] = !DILocation(line: 0, scope: [[S12]], inlinedAt: 
[[I15:!.*]])
+// CHECK: [[I15]] = !DILocation(line: 66,
 // CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
-// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)
-// CHECK: [[G7R1]] = !DILocation({{.*}}, atomGroup: 7, atomRank: 1)
-// CHECK: [[G8R1]] = !DILocation({{.*}}, atomGroup: 8, atomRank: 1)
-// CHECK: [[G9R1]] = !DILocation({{.*}}, atomGroup: 9, atomRank: 1)
-// CHECK: [[G10R1]] = !DILocation({{.*}}, atomGroup: 10, atomRank: 1)
-// CHECK: [[G11R1]] = !DILocation({{.*}}, atomGroup: 11, atomRank: 1)
-// CHECK: [[G12R1]] = !DILocation({{.*}}, atomGroup: 12, atomRank: 1)
-// CHECK: [[G13R1]] = !DILocation({{.*}}, atomGroup: 13, atomRank: 1)
-// CHECK: [[G14R1]] = !DILocation({{.*}}, atomGroup: 14, atomRank: 1)
-// CHECK: [[G15R3]] = !DILocation({{.*}}, atomGroup: 15, atomRank: 3)
-// CHECK: [[G15R2]] = !DILocation({{.*}}, atomGroup: 15, atomRank: 2)
-// CHECK: [[G15R1]] = !DILocation({{.*}}, atomGroup: 15, atomRank: 1)
-// CHECK: [[RET]] = !DILocation({{.*}}, atomGroup: 16, atomRank: 1)

>From 96ff6144a1f250d02dc0f8b23069a8c9a7ac6846 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Thu, 2 Apr 2026 14:37:51 +0100
Subject: [PATCH 4/8] Adjust test
 CodeGenOpenCL/enqueue-kernel-non-entry-block.cl for inlined compiler
 built-ins

---
 clang/test/CodeGenOpenCL/enqueue-kernel-non-entry-block.cl | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenOpenCL/enqueue-kernel-non-entry-block.cl 
b/clang/test/CodeGenOpenCL/enqueue-kernel-non-entry-block.cl
index 8e970f121bca8..e927a188afc13 100644
--- a/clang/test/CodeGenOpenCL/enqueue-kernel-non-entry-block.cl
+++ b/clang/test/CodeGenOpenCL/enqueue-kernel-non-entry-block.cl
@@ -18,7 +18,7 @@ kernel void test(int i) {
 // SPIR64: %block_sizes = alloca [1 x i64]
 // COMMON-LABEL: if.then:
 // COMMON-NOT: alloca
-// CHECK-DEBUG: getelementptr {{.*}} %block_sizes{{.*}}, {{.*}} !dbg 
![[TEMPLOCATION:[0-9]+]]
+// CHECK-DEBUG: getelementptr {{.*}} %block_sizes{{.*}}, {{.*}} !dbg 
![[BUILTINLOCATION:[0-9]+]]
 // COMMON-LABEL: if.end
   queue_t default_queue;
   unsigned flags = 0;
@@ -38,4 +38,6 @@ kernel void test(int i) {
 // CHECK-DEBUG: ![[TESTFILE:[0-9]+]] = !DIFile(filename: "<stdin>"
 // CHECK-DEBUG: ![[TESTSCOPE:[0-9]+]] = distinct !DISubprogram(name: "test", 
linkageName: "__clang_ocl_kern_imp_test", {{.*}} file: ![[TESTFILE]]
 // CHECK-DEBUG: ![[IFSCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: 
![[TESTSCOPE]], file: ![[TESTFILE]], line: 26)
-// CHECK-DEBUG: ![[TEMPLOCATION]] = !DILocation(line: 27, scope: ![[IFSCOPE]])
+// CHECK-DEBUG: ![[TEMPLOCATION:[0-9]+]] = !DILocation(line: 27, scope: 
![[IFSCOPE]])
+// CHECK-DEBUG: ![[BUILTINLOCATION]] = !DILocation(line: 0, scope: 
![[BUILTINSCOPE:[0-9]+]], inlinedAt: ![[TEMPLOCATION]])
+// CHECK-DEBUG: ![[BUILTINSCOPE]] = distinct !DISubprogram(name: 
"enqueue_kernel"{{.*}}, flags: DIFlagArtificial

>From bd262ad4d5b8f99a32fa7610c947061e02db6f59 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Wed, 6 May 2026 16:47:22 +0100
Subject: [PATCH 5/8] Adjust compiler-rt tests for inlined compiler built-ins

---
 compiler-rt/test/dfsan/origin_memcpy.c        | 26 +++++++-------
 compiler-rt/test/dfsan/origin_memmove.c       | 26 +++++++-------
 .../test/dfsan/origin_unaligned_memtrans.c    | 36 ++++++++++---------
 compiler-rt/test/dfsan/pthread.c              |  7 ++--
 .../test/msan/chained_origin_memcpy.cpp       | 13 +++----
 .../test/msan/chained_origin_memmove.cpp      | 13 +++----
 6 files changed, 66 insertions(+), 55 deletions(-)

diff --git a/compiler-rt/test/dfsan/origin_memcpy.c 
b/compiler-rt/test/dfsan/origin_memcpy.c
index 5632f259ead86..03250baced10a 100644
--- a/compiler-rt/test/dfsan/origin_memcpy.c
+++ b/compiler-rt/test/dfsan/origin_memcpy.c
@@ -42,26 +42,28 @@ int main(int argc, char *argv[]) {
 
 // CHECK0: Taint value 0x8 {{.*}} origin tracking ()
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_h.dfsan {{.*}}origin_memcpy.c:[[@LINE-16]]
-// CHECK0: #1 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-8]]
+// CHECK0: #0 {{.*}} in memcpy {{.*}}origin_memcpy.c:[[@LINE-17]]
+// CHECK0: #1 {{.*}} in fn_h.dfsan {{.*}}origin_memcpy.c:[[@LINE-17]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-9]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memcpy.c:[[@LINE-30]]
-// CHECK0: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memcpy.c:[[@LINE-26]]
-// CHECK0: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-14]]
+// CHECK0: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memcpy.c:[[@LINE-31]]
+// CHECK0: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memcpy.c:[[@LINE-27]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-15]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was created at
-// CHECK0: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-19]]
+// CHECK0: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-20]]
 
 // CHECK10: Taint value 0x10 {{.*}} origin tracking ()
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_h.dfsan {{.*}}origin_memcpy.c:[[@LINE-29]]
-// CHECK10: #1 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-21]]
+// CHECK10: #0 {{.*}} in memcpy {{.*}}origin_memcpy.c:[[@LINE-31]]
+// CHECK10: #1 {{.*}} in fn_h.dfsan {{.*}}origin_memcpy.c:[[@LINE-31]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-23]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memcpy.c:[[@LINE-43]]
-// CHECK10: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memcpy.c:[[@LINE-39]]
-// CHECK10: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-27]]
+// CHECK10: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memcpy.c:[[@LINE-45]]
+// CHECK10: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memcpy.c:[[@LINE-41]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-29]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was created at
-// CHECK10: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-31]]
+// CHECK10: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-33]]
diff --git a/compiler-rt/test/dfsan/origin_memmove.c 
b/compiler-rt/test/dfsan/origin_memmove.c
index 9ec050428c69a..38a6d02302175 100644
--- a/compiler-rt/test/dfsan/origin_memmove.c
+++ b/compiler-rt/test/dfsan/origin_memmove.c
@@ -42,26 +42,28 @@ int main(int argc, char *argv[]) {
 
 // CHECK0: Taint value 0x8 {{.*}} origin tracking ()
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_h.dfsan {{.*}}origin_memmove.c:[[@LINE-16]]
-// CHECK0: #1 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-8]]
+// CHECK0: #0 {{.*}} in memmove {{.*}}origin_memmove.c:[[@LINE-17]]
+// CHECK0: #1 {{.*}} in fn_h.dfsan {{.*}}origin_memmove.c:[[@LINE-17]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-9]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memmove.c:[[@LINE-30]]
-// CHECK0: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memmove.c:[[@LINE-26]]
-// CHECK0: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-14]]
+// CHECK0: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memmove.c:[[@LINE-31]]
+// CHECK0: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memmove.c:[[@LINE-27]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-15]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was created at
-// CHECK0: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-19]]
+// CHECK0: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-20]]
 
 // CHECK10: Taint value 0x10 {{.*}} origin tracking ()
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_h.dfsan {{.*}}origin_memmove.c:[[@LINE-29]]
-// CHECK10: #1 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-21]]
+// CHECK10: #0 {{.*}} in memmove {{.*}}origin_memmove.c:[[@LINE-31]]
+// CHECK10: #1 {{.*}} in fn_h.dfsan {{.*}}origin_memmove.c:[[@LINE-31]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-23]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memmove.c:[[@LINE-43]]
-// CHECK10: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memmove.c:[[@LINE-39]]
-// CHECK10: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-27]]
+// CHECK10: #0 {{.*}} in fn_g.dfsan {{.*}}origin_memmove.c:[[@LINE-45]]
+// CHECK10: #1 {{.*}} in fn_f.dfsan {{.*}}origin_memmove.c:[[@LINE-41]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-29]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was created at
-// CHECK10: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-31]]
+// CHECK10: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-33]]
diff --git a/compiler-rt/test/dfsan/origin_unaligned_memtrans.c 
b/compiler-rt/test/dfsan/origin_unaligned_memtrans.c
index b465af1474fa3..35181b4254812 100644
--- a/compiler-rt/test/dfsan/origin_unaligned_memtrans.c
+++ b/compiler-rt/test/dfsan/origin_unaligned_memtrans.c
@@ -45,34 +45,38 @@ int main(int argc, char *argv[]) {
 
 // CHECK0: Taint value 0x8 {{.*}} origin tracking ()
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_i.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-18]]
-// CHECK0: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-8]]
+// CHECK0: #0 {{.*}} in memmove {{.*}}origin_unaligned_memtrans.c:[[@LINE-19]]
+// CHECK0: #1 {{.*}} in fn_i.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-19]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-9]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_h.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-26]]
-// CHECK0: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-13]]
+// CHECK0: #0 {{.*}} in memcpy {{.*}}origin_unaligned_memtrans.c:[[@LINE-28]]
+// CHECK0: #1 {{.*}} in fn_h.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-28]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-15]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK0: #0 {{.*}} in fn_g.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-38]]
-// CHECK0: #1 {{.*}} in fn_f.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-35]]
-// CHECK0: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-19]]
+// CHECK0: #0 {{.*}} in fn_g.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-40]]
+// CHECK0: #1 {{.*}} in fn_f.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-37]]
+// CHECK0: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-21]]
 
 // CHECK0: Origin value: {{.*}}, Taint value was created at
-// CHECK0: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-24]]
+// CHECK0: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-26]]
 
 // CHECK10: Taint value 0x10 {{.*}} origin tracking
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_i.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-35]]
-// CHECK10: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-25]]
+// CHECK10: #0 {{.*}} in memmove {{.*}}origin_unaligned_memtrans.c:[[@LINE-38]]
+// CHECK10: #1 {{.*}} in fn_i.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-38]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-28]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_h.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-43]]
-// CHECK10: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-30]]
+// CHECK10: #0 {{.*}} in memcpy {{.*}}origin_unaligned_memtrans.c:[[@LINE-47]]
+// CHECK10: #1 {{.*}} in fn_h.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-47]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-34]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK10: #0 {{.*}} in fn_g.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-55]]
-// CHECK10: #1 {{.*}} in fn_f.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-52]]
-// CHECK10: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-36]]
+// CHECK10: #0 {{.*}} in fn_g.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-59]]
+// CHECK10: #1 {{.*}} in fn_f.dfsan 
{{.*}}origin_unaligned_memtrans.c:[[@LINE-56]]
+// CHECK10: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-40]]
 
 // CHECK10: Origin value: {{.*}}, Taint value was created at
-// CHECK10: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-40]]
+// CHECK10: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-44]]
diff --git a/compiler-rt/test/dfsan/pthread.c b/compiler-rt/test/dfsan/pthread.c
index c5b195c76998d..6db6a3342b144 100644
--- a/compiler-rt/test/dfsan/pthread.c
+++ b/compiler-rt/test/dfsan/pthread.c
@@ -42,10 +42,11 @@ int main(void) {
 
 // CHECK: Taint value 0x8 {{.*}} origin tracking ()
 // CHECK: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK: #0 {{.*}} in ThreadFn.dfsan {{.*}}pthread.c:[[@LINE-21]]
+// CHECK: #0 {{.*}} in memcpy {{.*}}pthread.c
+// CHECK: #1 {{.*}} in ThreadFn.dfsan {{.*}}pthread.c:[[@LINE-22]]
 
 // CHECK: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK: #0 {{.*}} in ThreadFn.dfsan {{.*}}pthread.c:[[@LINE-26]]
+// CHECK: #0 {{.*}} in ThreadFn.dfsan {{.*}}pthread.c:[[@LINE-27]]
 
 // CHECK: Origin value: {{.*}}, Taint value was created at
-// CHECK: #0 {{.*}} in main {{.*}}pthread.c:[[@LINE-20]]
+// CHECK: #0 {{.*}} in main {{.*}}pthread.c:[[@LINE-21]]
diff --git a/compiler-rt/test/msan/chained_origin_memcpy.cpp 
b/compiler-rt/test/msan/chained_origin_memcpy.cpp
index 8961b4cd64da6..1195df9fedc5a 100644
--- a/compiler-rt/test/msan/chained_origin_memcpy.cpp
+++ b/compiler-rt/test/msan/chained_origin_memcpy.cpp
@@ -48,15 +48,16 @@ int main(int argc, char *argv[]) {
 // CHECK: {{#0 .* in main .*chained_origin_memcpy.cpp:}}[[@LINE-4]]
 
 // CHECK: Uninitialized value was stored to memory at
-// CHECK-FULL-STACK: {{#1 .* in fn_h.*chained_origin_memcpy.cpp:}}[[@LINE-15]]
+// CHECK-FULL-STACK: {{#1 .* in 
memcpy.*chained_origin_memcpy.cpp:}}[[@LINE-16]]
+// CHECK-FULL-STACK: {{#2 .* in fn_h.*chained_origin_memcpy.cpp:}}[[@LINE-16]]
 // CHECK-SHORT-STACK: {{#0 .* in __msan_memcpy.*msan_interceptors.cpp:}}
 
 // CHECK: Uninitialized value was stored to memory at
-// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cpp:}}[[@LINE-29]]
-// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memcpy.cpp:}}[[@LINE-25]]
-// CHECK-SHORT-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cpp:}}[[@LINE-31]]
+// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cpp:}}[[@LINE-30]]
+// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memcpy.cpp:}}[[@LINE-26]]
+// CHECK-SHORT-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cpp:}}[[@LINE-32]]
 
 // CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the 
stack frame
 // CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the 
stack frame
-// CHECK-Z1: {{#0 .* in main.*chained_origin_memcpy.cpp:}}[[@LINE-21]]
-// CHECK-Z2: {{#0 .* in main.*chained_origin_memcpy.cpp:}}[[@LINE-21]]
+// CHECK-Z1: {{#0 .* in main.*chained_origin_memcpy.cpp:}}[[@LINE-22]]
+// CHECK-Z2: {{#0 .* in main.*chained_origin_memcpy.cpp:}}[[@LINE-22]]
diff --git a/compiler-rt/test/msan/chained_origin_memmove.cpp 
b/compiler-rt/test/msan/chained_origin_memmove.cpp
index fcaf3735bd9d1..8fa5f3b5fb439 100644
--- a/compiler-rt/test/msan/chained_origin_memmove.cpp
+++ b/compiler-rt/test/msan/chained_origin_memmove.cpp
@@ -44,15 +44,16 @@ int main(int argc, char *argv[]) {
 // CHECK: {{#0 .* in main .*chained_origin_memmove.cpp:}}[[@LINE-4]]
 
 // CHECK: Uninitialized value was stored to memory at
-// CHECK-FULL-STACK: {{#1 .* in fn_h.*chained_origin_memmove.cpp:}}[[@LINE-15]]
+// CHECK-FULL-STACK: {{#1 .* in 
memmove.*chained_origin_memmove.cpp:}}[[@LINE-16]]
+// CHECK-FULL-STACK: {{#2 .* in fn_h.*chained_origin_memmove.cpp:}}[[@LINE-16]]
 // CHECK-SHORT-STACK: {{#0 .* in __msan_memmove.*msan_interceptors.cpp:}}
 
 // CHECK: Uninitialized value was stored to memory at
-// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memmove.cpp:}}[[@LINE-27]]
-// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memmove.cpp:}}[[@LINE-24]]
-// CHECK-SHORT-STACK: {{#0 .* in 
fn_g.*chained_origin_memmove.cpp:}}[[@LINE-29]]
+// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memmove.cpp:}}[[@LINE-28]]
+// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memmove.cpp:}}[[@LINE-25]]
+// CHECK-SHORT-STACK: {{#0 .* in 
fn_g.*chained_origin_memmove.cpp:}}[[@LINE-30]]
 
 // CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the 
stack frame
 // CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the 
stack frame
-// CHECK-Z1: {{#0 .* in main.*chained_origin_memmove.cpp:}}[[@LINE-21]]
-// CHECK-Z2: {{#0 .* in main.*chained_origin_memmove.cpp:}}[[@LINE-21]]
+// CHECK-Z1: {{#0 .* in main.*chained_origin_memmove.cpp:}}[[@LINE-22]]
+// CHECK-Z2: {{#0 .* in main.*chained_origin_memmove.cpp:}}[[@LINE-22]]

>From f7d0d469bb8d39e680d63efc3378b86809050f29 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Thu, 7 May 2026 15:10:01 +0100
Subject: [PATCH 6/8] Add enabled-by-default flag for inlined compiler
 built-ins

---
 clang/include/clang/Basic/DebugOptions.def |  5 +++++
 clang/include/clang/Options/Options.td     |  8 ++++++++
 clang/lib/CodeGen/CGBuiltin.cpp            |  3 ++-
 clang/lib/Driver/ToolChains/Clang.cpp      |  4 ++++
 clang/test/DebugInfo/Generic/builtin.c     | 16 ++++++++++------
 clang/test/Driver/debug-options.c          |  5 +++++
 6 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/DebugOptions.def 
b/clang/include/clang/Basic/DebugOptions.def
index 604e87e615a69..f9366a22b5f05 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -68,6 +68,11 @@ DEBUGOPT(DebugColumnInfo, 1, 0, Compatible) ///< Whether or 
not to use column in
 /// Whether or not to include call site information in debug info.
 DEBUGOPT(DebugCallSiteInfo, 1, 1, Benign)
 
+/// Whether to represent built-ins as calls to artificial inlined functions in
+/// debug info. This enables e.g. profiling tools to annotate time spent in
+/// user-called built-ins with the built-in function name.
+DEBUGOPT(DebugInlinedBuiltins, 1, 1, Benign)
+
 DEBUGOPT(DebugTypeExtRefs, 1, 0, Compatible) ///< Whether or not debug info 
should contain
                                             ///< external references to a PCH 
or module.
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 46e97256a9e77..68593a19513fc 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5174,6 +5174,14 @@ def gembed_source : Flag<["-"], "gembed-source">, 
Group<g_flags_Group>,
 def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
     Flags<[NoXarchOption]>,
     HelpText<"Restore the default behavior of not embedding source text in 
DWARF debug sections">;
+defm inlined_builtins : BoolOption<"g", "inlined-builtins",
+  CodeGenOpts<"DebugInlinedBuiltins">,
+  DefaultTrue,
+  PosFlag<SetTrue, [], [], "Enable">,
+  NegFlag<SetFalse, [], [], "Disable">,
+  BothFlags<[], [ClangOption, CC1Option], " inlined compiler built-ins in 
debug info">>,
+  Group<g_flags_Group>,
+  DocBrief<[{Treats built-ins as calls to artificial inlined functions in 
debug info. This enables e.g. profiling tools to annotate time spent in 
user-called built-ins with the built-in function name.}]>;
 defm structor_decl_linkage_names
     : BoolGOption<"structor-decl-linkage-names",
                   CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 94f6344249851..5de8c0046d915 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2769,7 +2769,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
   // built-ins with the built-in function name.
   // See `useBuiltinDebugLocation` for cases where this treatment is disabled.
   auto DebugScope =
-      shouldUseBuiltinDebugLocation(BuiltinID)
+      CGM.getCodeGenOpts().DebugInlinedBuiltins &&
+              shouldUseBuiltinDebugLocation(BuiltinID)
           ? std::make_optional<ApplyBuiltinDebugLocation>(*this, GD)
           : std::nullopt;
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 99f511df9e8a1..a356c062f4d0a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4599,6 +4599,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, 
const llvm::Triple &T,
                     options::OPT_gno_call_site_info, true))
     CmdArgs.push_back("-gno-call-site-info");
 
+  if (!Args.hasFlag(options::OPT_ginlined_builtins,
+                    options::OPT_gno_inlined_builtins, true))
+    CmdArgs.push_back("-gno-inlined-builtins");
+
   // FIXME: Move backend command line options to the module.
   if (Args.hasFlag(options::OPT_gmodules, options::OPT_gno_modules, false)) {
     // If -gline-tables-only or -gline-directives-only is the last option it
diff --git a/clang/test/DebugInfo/Generic/builtin.c 
b/clang/test/DebugInfo/Generic/builtin.c
index f6aa94de53f21..c885302b20e48 100644
--- a/clang/test/DebugInfo/Generic/builtin.c
+++ b/clang/test/DebugInfo/Generic/builtin.c
@@ -1,5 +1,6 @@
 
 // RUN: %clang_cc1 -triple x86_64-linux-gnu %s -debug-info-kind=limited 
-emit-llvm -disable-llvm-passes -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -debug-info-kind=limited 
-gno-inlined-builtins -emit-llvm -disable-llvm-passes -o - | FileCheck %s 
--check-prefix=CHECK-DISABLED
 
 void fun() {
     // Most call-like built-ins are wrapped in an artificial inlined function 
in
@@ -29,23 +30,26 @@ void fun() {
 
 // CHECK: [[B1]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I1:!.*]])
 // CHECK: [[S1]] = distinct !DISubprogram(name: "__builtin_alloca"{{.*}}, 
flags: DIFlagArtificial
-// CHECK: [[I1]] = !DILocation(line: 8,
+// CHECK: [[I1]] = !DILocation(line: 9,
 
 // Second call should reuse same `DISubprogram` scope.
 // CHECK: [[B2]] = !DILocation(line: 0, scope: [[S1:!.*]], inlinedAt: 
[[I2:!.*]])
-// CHECK: [[I2]] = !DILocation(line: 12,
+// CHECK: [[I2]] = !DILocation(line: 13,
 
 // CHECK: [[B3]] = !DILocation(line: 0, scope: [[S3:!.*]], inlinedAt: 
[[I3:!.*]])
 // CHECK: [[S3]] = distinct !DISubprogram(name: "__builtin_memset"{{.*}}, 
flags: DIFlagArtificial
-// CHECK: [[I3]] = !DILocation(line: 15,
+// CHECK: [[I3]] = !DILocation(line: 16,
 
 // Excluded built-ins should use location without inlined function wrapper.
 
-// CHECK: [[B4]] = !DILocation(line: 19,
+// CHECK: [[B4]] = !DILocation(line: 20,
 // CHECK-NOT: distinct !DISubprogram(name: "__builtin_assume"{{.*}}, flags: 
DIFlagArtificial
 
-// CHECK: [[B5]] = !DILocation(line: 23,
+// CHECK: [[B5]] = !DILocation(line: 24,
 // CHECK-NOT: distinct !DISubprogram(name: "__builtin_ia32_rdtsc"{{.*}}, 
flags: DIFlagArtificial
 
-// CHECK: [[B6]] = !DILocation(line: 27,
+// CHECK: [[B6]] = !DILocation(line: 28,
 // CHECK-NOT: distinct !DISubprogram(name: "__builtin_malloc"{{.*}}, flags: 
DIFlagArtificial
+
+// When disabled, there should not be any artificial subprograms
+// CHECK-DISABLED-NOT: distinct !DISubprogram({{.*}}, flags: DIFlagArtificial
diff --git a/clang/test/Driver/debug-options.c 
b/clang/test/Driver/debug-options.c
index 92179ff9421ad..155dc273fecb9 100644
--- a/clang/test/Driver/debug-options.c
+++ b/clang/test/Driver/debug-options.c
@@ -300,6 +300,9 @@
 // RUN: %clang -### -g -gno-call-site-info %s 2>&1 \
 // RUN:        | FileCheck -check-prefix=NOCALLSITE %s
 //
+// RUN: %clang -### -g -gno-inlined-builtins %s 2>&1 \
+// RUN:        | FileCheck -check-prefix=NOINLINEDBUILTINS %s
+//
 // RUN: %clang -### -g -target x86_64-unknown-unknown %s 2>&1 \
 //             | FileCheck -check-prefix=CI %s
 //
@@ -431,6 +434,8 @@
 //
 // NOCALLSITE: "-gno-call-site-info"
 //
+// NOINLINEDBUILTINS: "-gno-inlined-builtins"
+//
 // GEXTREFS: "-dwarf-ext-refs" "-fmodule-format=obj"
 // GEXTREFS: "-debug-info-kind={{standalone|constructor}}"
 // NOGEXTREFS-NOT: -dwarf-ext-refs

>From 8ac732ac22439d9581b780b0ddce599c56369c4f Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Thu, 7 May 2026 16:00:43 +0100
Subject: [PATCH 7/8] Adjust compiler-rt tests on Windows for inlined compiler
 built-ins

---
 .../test/asan/TestCases/Windows/dll_intercept_memcpy.cpp        | 2 +-
 .../test/asan/TestCases/Windows/dll_intercept_memset.cpp        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memcpy.cpp 
b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memcpy.cpp
index 4fa437960f126..647685b68d8f1 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memcpy.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memcpy.cpp
@@ -26,7 +26,7 @@ int test_function() {
   // CHECK: AddressSanitizer: stack-buffer-overflow on address 
[[ADDR:0x[0-9a-f]+]]
   // CHECK: WRITE of size 6 at [[ADDR]] thread T0
   // CHECK-NEXT:  __asan_{{.*}}{{(memcpy|memmove)}}
-  // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy.cpp:[[@LINE-4]]
+  // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy.cpp:[[@LINE-7]]
   // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} 
in frame
   // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy.cpp
   // CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this 
variable
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp 
b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
index 948a429e8c1a6..fd9d910be672c 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
@@ -26,7 +26,7 @@ int test_function() {
 // CHECK: AddressSanitizer: stack-buffer-overflow on address 
[[ADDR:0x[0-9a-f]+]]
 // CHECK: WRITE of size 6 at [[ADDR]] thread T0
 // CHECK-NEXT:  __asan_memset
-// CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp:[[@LINE-4]]
+// CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp:[[@LINE-7]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} 
in frame
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp
 // CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this 
variable

>From 9af540b10c2d9b01228d94150619e159edc26c5c Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <[email protected]>
Date: Thu, 7 May 2026 16:06:11 +0100
Subject: [PATCH 8/8] Format adjusted tests

---
 .../TestCases/Windows/dll_intercept_memset.cpp     | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp 
b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
index fd9d910be672c..8d1fc9f441002 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_intercept_memset.cpp
@@ -23,12 +23,12 @@ int test_function() {
 // CHECK: Initial test OK
 
   memset(buff, 'c', 6);
-// CHECK: AddressSanitizer: stack-buffer-overflow on address 
[[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 6 at [[ADDR]] thread T0
-// CHECK-NEXT:  __asan_memset
-// CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp:[[@LINE-7]]
-// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} 
in frame
-// CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp
-// CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this 
variable
+  // CHECK: AddressSanitizer: stack-buffer-overflow on address 
[[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 6 at [[ADDR]] thread T0
+  // CHECK-NEXT:  __asan_memset
+  // CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp:[[@LINE-7]]
+  // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} 
in frame
+  // CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cpp
+  // CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this 
variable
   return 0;
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to