[clang] [clang-tools-extra] [clang][AST] Fix StmtProfile handling of GCCAsmStmt asm strings and clobbers (PR #201481)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 14 22:51:56 PDT 2026
https://github.com/IamYJLee updated https://github.com/llvm/llvm-project/pull/201481
>From a36709653a16ce9c90545e6f398d7910bde9677c Mon Sep 17 00:00:00 2001
From: LeeYoungJoon <dog3hk.dev at gmail.com>
Date: Thu, 4 Jun 2026 09:14:15 +0900
Subject: [PATCH 1/5] [clang][AST] Fix StmtProfile handling of GCCAsmStmt asm
strings and clobbers
did not profile asm strings and clobbers because they are not child statements. As a result, different inline asm statements could produce the same profile.
This fixes a false positive in where branches containing inline asm were incorrectly reported as identical.
---
clang/lib/AST/StmtProfile.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index eb25e5260fd1a..9b64fda3bd339 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -329,7 +329,7 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
VisitStmt(S);
ID.AddBoolean(S->isVolatile());
ID.AddBoolean(S->isSimple());
- VisitExpr(S->getAsmStringExpr());
+ Visit(S->getAsmStringExpr());
ID.AddInteger(S->getNumOutputs());
for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
ID.AddString(S->getOutputName(I));
@@ -342,7 +342,7 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
}
ID.AddInteger(S->getNumClobbers());
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
- VisitExpr(S->getClobberExpr(I));
+ Visit(S->getClobberExpr(I));
ID.AddInteger(S->getNumLabels());
for (auto *L : S->labels())
VisitDecl(L->getLabel());
>From 3486463fdab1cf12e4738d9ede2f184bd8a4ba24 Mon Sep 17 00:00:00 2001
From: LeeYoungJoon <dog3hk.dev at gmail.com>
Date: Thu, 4 Jun 2026 16:58:21 +0900
Subject: [PATCH 2/5] Add test case for branch clone inline asm
---
.../bugprone/branch-clone-inline-asm.cpp | 75 +++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
new file mode 100644
index 0000000000000..05027fb18b5ab
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy %s bugprone-branch-clone %t --
+
+int test_asm1(int argc, char**) {
+ if (argc > 1) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
+ __asm__ volatile(
+ "addi %0, %0, -1"
+ : "+r" (argc)
+ );
+ } else {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here
+ __asm__ volatile(
+ "addi %0, %0, -1"
+ : "+r" (argc)
+ );
+ }
+ return argc;
+}
+
+int test_asm2(int argc, char**) {
+ if (argc > 1) { // no-warning
+ __asm__ volatile(
+ "addi %0, %0, -1"
+ : "+r" (argc)
+ );
+ } else {
+ __asm__ volatile(
+ "addi %0, %0, -2"
+ : "+r" (argc)
+ );
+ }
+ return argc;
+}
+
+int test_asm3(int argc, char**) {
+ int Test1 = 0;
+ if (argc > 1) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
+ __asm__ volatile(
+ "add %w0, %w0, -1"
+ : "+r" (argc)
+ : "r" (Test1)
+ : "w0"
+ );
+ } else {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here
+ __asm__ volatile(
+ "add %w0, %w0, -1"
+ : "+r" (argc)
+ : "r" (Test1)
+ : "w0"
+ );
+ }
+ return argc;
+}
+
+int test_asm4(int argc, char**) {
+ int Test1 = 0;
+ if (argc > 1) { // no-warning
+ __asm__ volatile(
+ "add %w0, %w0, -1"
+ : "+r" (argc)
+ : "r" (Test1)
+ : "w0"
+ );
+ } else {
+ __asm__ volatile(
+ "add %w0, %w0, -1"
+ : "+r" (argc)
+ : "r" (Test1)
+ : "w1"
+ );
+ }
+ return argc;
+}
\ No newline at end of file
>From 0d0b11049a88fb1bdfa1249e1b0547ecdfbcf525 Mon Sep 17 00:00:00 2001
From: LeeYoungJoon <dog3hk.dev at gmail.com>
Date: Wed, 10 Jun 2026 08:23:48 +0900
Subject: [PATCH 3/5] Fix test case to be target-independent
---
.../bugprone/branch-clone-inline-asm.cpp | 48 ++++---------------
1 file changed, 8 insertions(+), 40 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
index 05027fb18b5ab..1e12cbe43632d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
@@ -3,31 +3,19 @@
int test_asm1(int argc, char**) {
if (argc > 1) {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
- __asm__ volatile(
- "addi %0, %0, -1"
- : "+r" (argc)
- );
+ __asm__ volatile("" : "+r" (argc));
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here
- __asm__ volatile(
- "addi %0, %0, -1"
- : "+r" (argc)
- );
+ __asm__ volatile("" : "+r" (argc));
}
return argc;
}
int test_asm2(int argc, char**) {
if (argc > 1) { // no-warning
- __asm__ volatile(
- "addi %0, %0, -1"
- : "+r" (argc)
- );
+ __asm__ volatile("foo" : "+r" (argc));
} else {
- __asm__ volatile(
- "addi %0, %0, -2"
- : "+r" (argc)
- );
+ __asm__ volatile("bar" : "+r" (argc));
}
return argc;
}
@@ -36,20 +24,10 @@ int test_asm3(int argc, char**) {
int Test1 = 0;
if (argc > 1) {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
- __asm__ volatile(
- "add %w0, %w0, -1"
- : "+r" (argc)
- : "r" (Test1)
- : "w0"
- );
+ __asm__ volatile("" : "+r" (argc) : "r" (Test1) : "memory");
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here
- __asm__ volatile(
- "add %w0, %w0, -1"
- : "+r" (argc)
- : "r" (Test1)
- : "w0"
- );
+ __asm__ volatile("" : "+r" (argc) : "r" (Test1) : "memory");
}
return argc;
}
@@ -57,19 +35,9 @@ int test_asm3(int argc, char**) {
int test_asm4(int argc, char**) {
int Test1 = 0;
if (argc > 1) { // no-warning
- __asm__ volatile(
- "add %w0, %w0, -1"
- : "+r" (argc)
- : "r" (Test1)
- : "w0"
- );
+ __asm__ volatile("" : "+r" (argc) : "r" (Test1) : "memory");
} else {
- __asm__ volatile(
- "add %w0, %w0, -1"
- : "+r" (argc)
- : "r" (Test1)
- : "w1"
- );
+ __asm__ volatile("" : "+r" (argc) : "r" (Test1) : "cc");
}
return argc;
}
\ No newline at end of file
>From 8ddfa5ed461cb2632398519e71f81f14aba91530 Mon Sep 17 00:00:00 2001
From: LeeYoungJoon <dog3hk.dev at gmail.com>
Date: Wed, 10 Jun 2026 16:58:16 +0900
Subject: [PATCH 4/5] [clang-tidy] Address review comments for inline asm test
---
.../clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
index 1e12cbe43632d..daf9b539ae50a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/branch-clone-inline-asm.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-branch-clone %t --
+// RUN: %check_clang_tidy %s bugprone-branch-clone %t
int test_asm1(int argc, char**) {
if (argc > 1) {
@@ -40,4 +40,4 @@ int test_asm4(int argc, char**) {
__asm__ volatile("" : "+r" (argc) : "r" (Test1) : "cc");
}
return argc;
-}
\ No newline at end of file
+}
>From 25f61e307a97d9c0d4cee4eed372bff512625ad9 Mon Sep 17 00:00:00 2001
From: LeeYoungJoon <dog3hk.dev at gmail.com>
Date: Mon, 15 Jun 2026 14:51:37 +0900
Subject: [PATCH 5/5] [clang][modules] Add ODR test for inline-asm string and
clobber profiling
---
clang/test/Modules/asm-stmt-odr.cppm | 67 ++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 clang/test/Modules/asm-stmt-odr.cppm
diff --git a/clang/test/Modules/asm-stmt-odr.cppm b/clang/test/Modules/asm-stmt-odr.cppm
new file mode 100644
index 0000000000000..e065f9211efdb
--- /dev/null
+++ b/clang/test/Modules/asm-stmt-odr.cppm
@@ -0,0 +1,67 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -x c++ -std=c++20 %t/A.cppm -I%t -emit-module-interface -o %t/A.pcm
+// RUN: %clang_cc1 -x c++ -std=c++20 %t/B.cppm -I%t -emit-module-interface -o %t/B.pcm
+// RUN: %clang_cc1 -x c++ -std=c++20 -fprebuilt-module-path=%t %t/use.cpp -verify
+//
+// RUN: rm %t/A.pcm %t/B.pcm
+// RUN: %clang_cc1 -x c++ -std=c++20 %t/A.cppm -I%t -emit-reduced-module-interface -o %t/A.pcm
+// RUN: %clang_cc1 -x c++ -std=c++20 %t/B.cppm -I%t -emit-reduced-module-interface -o %t/B.pcm
+// RUN: %clang_cc1 -x c++ -std=c++20 -fprebuilt-module-path=%t %t/use.cpp -verify
+
+// Regression test for the StmtProfiler::VisitGCCAsmStmt fix in
+// clang/lib/AST/StmtProfile.cpp (using Visit() so StringLiteral bytes are
+// folded into the FoldingSetNodeID, and therefore into the ODR hash).
+// Without the fix, two inline functions whose only difference is the inline
+// asm body produce the same ODR hash, get merged across modules, and no
+// diagnostic is emitted at the use site.
+
+//--- a.h
+inline int asm_string_func() {
+ int x = 0;
+ __asm__("foo" : "+r"(x));
+ return x;
+}
+inline int clobber_func() {
+ int x = 0;
+ __asm__("" : "+r"(x) : : "memory");
+ return x;
+}
+
+//--- a.v1.h
+inline int asm_string_func() {
+ int x = 0;
+ __asm__("bar" : "+r"(x)); // differs from a.h: asm string
+ return x;
+}
+inline int clobber_func() {
+ int x = 0;
+ __asm__("" : "+r"(x) : : "cc"); // differs from a.h: clobber
+ return x;
+}
+
+//--- A.cppm
+module;
+#include "a.h"
+export module A;
+export using ::asm_string_func;
+export using ::clobber_func;
+
+//--- B.cppm
+module;
+#include "a.v1.h"
+export module B;
+export using ::asm_string_func;
+export using ::clobber_func;
+
+//--- use.cpp
+import A;
+import B;
+// expected-error@*:* 1+{{'asm_string_func' has different definitions in different modules}}
+// expected-error@*:* 1+{{'clobber_func' has different definitions in different modules}}
+// expected-note@*:* 1+{{but in 'A.<global>' found a different body}}
+
+int u1 = asm_string_func();
+int u2 = clobber_func();
More information about the cfe-commits
mailing list