[clang] [NFC][clang][test] Split inline builtin tests and add strlen test (PR #234414)
Vitaly Buka via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 21 20:00:30 PDT 2026
https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/234414
>From 55e650809abb5b99bb0c1da850391f3eb469085a Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Wed, 21 Oct 2026 15:41:47 -0700
Subject: [PATCH 1/2] split and address review comments
Created using spr 2.0.0-beta.1
---
clang/test/CodeGen/memcmp-inline-builtin.c | 24 ++++
.../CodeGen/memcpy-inline-builtin-no-extern.c | 112 ++----------------
clang/test/CodeGen/strlen-inline-builtin.c | 25 ++++
clang/test/CodeGen/umask-inline-builtin.c | 20 ++++
4 files changed, 76 insertions(+), 105 deletions(-)
create mode 100644 clang/test/CodeGen/memcmp-inline-builtin.c
create mode 100644 clang/test/CodeGen/strlen-inline-builtin.c
create mode 100644 clang/test/CodeGen/umask-inline-builtin.c
diff --git a/clang/test/CodeGen/memcmp-inline-builtin.c b/clang/test/CodeGen/memcmp-inline-builtin.c
new file mode 100644
index 0000000000000..c018ce2ccceae
--- /dev/null
+++ b/clang/test/CodeGen/memcmp-inline-builtin.c
@@ -0,0 +1,24 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --filter "call " --include-generated-funcs --version 6
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+typedef unsigned long size_t;
+
+extern inline __attribute__((always_inline)) __attribute__((gnu_inline))
+int memcmp(const void *a, const void *b, size_t c) {
+ return __builtin_memcmp(a, b, c);
+}
+
+int bar(const void *a, const void *b, size_t c) {
+ return memcmp(a, b, c);
+}
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define dso_local i32 @bar(
+// CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]], i64 noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = call i32 @memcmp.inline(ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]], i64 noundef [[TMP2:%.*]])
+//
+//
+// CHECK: Function Attrs: alwaysinline nounwind
+// CHECK-LABEL: define internal i32 @memcmp.inline(
+// CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = call i32 @memcmp(ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]], i64 noundef [[TMP2:%.*]]) #[[ATTR3:[0-9]+]]
+//
diff --git a/clang/test/CodeGen/memcpy-inline-builtin-no-extern.c b/clang/test/CodeGen/memcpy-inline-builtin-no-extern.c
index a373346f5fcee..4cb0b5f06309c 100644
--- a/clang/test/CodeGen/memcpy-inline-builtin-no-extern.c
+++ b/clang/test/CodeGen/memcpy-inline-builtin-no-extern.c
@@ -1,123 +1,25 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --include-generated-funcs --version 6
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --filter "call " --include-generated-funcs --version 6
// RUN: %clang_cc1 -triple x86_64 -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-// Verifies that clang-generated *.inline are flagged as internal.
typedef unsigned long size_t;
-#define AVAILABLE_EXTERNALLY extern inline __attribute__((always_inline)) __attribute__((gnu_inline))
-// Clang recognizes an inline builtin and renames it to memcmp.inline to prevent conflict with builtins.
-AVAILABLE_EXTERNALLY int memcmp(const void *a, const void *b, size_t c) {
- return __builtin_memcmp(a, b, c);
-}
-
-int bar(const void *a, const void *b, size_t c) {
- return memcmp(a, b, c);
-}
-
// Note that extern has been omitted here.
-#define TRIPLE_INLINE inline __attribute__((always_inline)) __attribute__((gnu_inline))
-
-// Clang recognizes an inline builtin and renames it to memcpy.inline to prevent conflict with builtins.
-TRIPLE_INLINE void *memcpy(void *a, const void *b, size_t c) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline))
+void *memcpy(void *a, const void *b, size_t c) {
return __builtin_memcpy(a, b, c);
}
void *foo(void *a, const void *b, size_t c) {
return memcpy(a, b, c);
}
-
-AVAILABLE_EXTERNALLY __attribute__((preserve_most)) int umask(int m) {
- return m;
-}
-
-int call_umask(int m) {
- return umask(m);
-}
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: define dso_local i32 @bar(
-// CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]], i64 noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i64, align 8
-// CHECK-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
-// CHECK-NEXT: store i64 [[C]], ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ADDR]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[CALL:%.*]] = call i32 @memcmp.inline(ptr noundef [[TMP0]], ptr noundef [[TMP1]], i64 noundef [[TMP2]])
-// CHECK-NEXT: ret i32 [[CALL]]
-//
-//
-// CHECK: Function Attrs: alwaysinline nounwind
-// CHECK-LABEL: define internal i32 @memcmp.inline(
-// CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i64, align 8
-// CHECK-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
-// CHECK-NEXT: store i64 [[C]], ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ADDR]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[CALL:%.*]] = call i32 @memcmp(ptr noundef [[TMP0]], ptr noundef [[TMP1]], i64 noundef [[TMP2]]) #[[ATTR4:[0-9]+]]
-// CHECK-NEXT: ret i32 [[CALL]]
-//
-//
// CHECK: Function Attrs: alwaysinline nounwind
// CHECK-LABEL: define internal ptr @memcpy.inline(
-// CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[C:%.*]]) #[[ATTR2]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i64, align 8
-// CHECK-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
-// CHECK-NEXT: store i64 [[C]], ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ADDR]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[C_ADDR]], align 8
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[TMP0]], ptr align 1 [[TMP1]], i64 [[TMP2]], i1 false)
-// CHECK-NEXT: ret ptr [[TMP0]]
+// CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[C:%.*]]) #[[ATTR1:[0-9]+]] {
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[TMP0:%.*]], ptr align 1 [[TMP1:%.*]], i64 [[TMP2:%.*]], i1 false)
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define dso_local ptr @foo(
-// CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]], i64 noundef [[C:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i64, align 8
-// CHECK-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
-// CHECK-NEXT: store i64 [[C]], ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ADDR]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[C_ADDR]], align 8
-// CHECK-NEXT: [[CALL:%.*]] = call ptr @memcpy.inline(ptr noundef [[TMP0]], ptr noundef [[TMP1]], i64 noundef [[TMP2]]) #[[ATTR4]]
-// CHECK-NEXT: ret ptr [[CALL]]
-//
-//
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: define dso_local i32 @call_umask(
-// CHECK-SAME: i32 noundef [[M:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[M_ADDR:%.*]] = alloca i32, align 4
-// CHECK-NEXT: store i32 [[M]], ptr [[M_ADDR]], align 4
-// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[M_ADDR]], align 4
-// CHECK-NEXT: [[CALL:%.*]] = call preserve_mostcc i32 @umask.inline(i32 noundef [[TMP0]]) #[[ATTR4]]
-// CHECK-NEXT: ret i32 [[CALL]]
-//
-//
-// CHECK: Function Attrs: alwaysinline nounwind
-// CHECK-LABEL: define internal i32 @umask.inline(
-// CHECK-SAME: i32 [[M:%.*]]) #[[ATTR2]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[M_ADDR:%.*]] = alloca i32, align 4
-// CHECK-NEXT: store i32 [[M]], ptr [[M_ADDR]], align 4
-// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[M_ADDR]], align 4
-// CHECK-NEXT: ret i32 [[TMP0]]
+// CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]], i64 noundef [[C:%.*]]) #[[ATTR3:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = call ptr @memcpy.inline(ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]], i64 noundef [[TMP2:%.*]]) #[[ATTR4:[0-9]+]]
//
diff --git a/clang/test/CodeGen/strlen-inline-builtin.c b/clang/test/CodeGen/strlen-inline-builtin.c
new file mode 100644
index 0000000000000..f24f5adb6b490
--- /dev/null
+++ b/clang/test/CodeGen/strlen-inline-builtin.c
@@ -0,0 +1,25 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --filter "call " --include-generated-funcs --version 6
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+typedef unsigned long size_t;
+
+size_t strlen(const char *s);
+void *strlen_ptr = strlen;
+
+extern inline __attribute__((always_inline)) __attribute__((gnu_inline))
+__attribute__((section("my_sec"))) size_t strlen(const char *s) {
+ return 0;
+}
+
+size_t call_strlen(const char *s) {
+ return strlen(s);
+}
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define dso_local i64 @call_strlen(
+// CHECK-SAME: ptr noundef [[S:%.*]]) #[[ATTR1:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = call i64 @strlen.inline(ptr noundef [[TMP0:%.*]]) #[[ATTR3:[0-9]+]]
+//
+//
+// CHECK: Function Attrs: alwaysinline nounwind
+// CHECK-LABEL: define internal i64 @strlen.inline(
+// CHECK-SAME: ptr [[S:%.*]]) #[[ATTR2:[0-9]+]] {
diff --git a/clang/test/CodeGen/umask-inline-builtin.c b/clang/test/CodeGen/umask-inline-builtin.c
new file mode 100644
index 0000000000000..1b66b9dff1bdb
--- /dev/null
+++ b/clang/test/CodeGen/umask-inline-builtin.c
@@ -0,0 +1,20 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --filter "call " --include-generated-funcs --version 6
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+extern inline __attribute__((always_inline)) __attribute__((gnu_inline))
+__attribute__((preserve_most)) int umask(int m) {
+ return m;
+}
+
+int call_umask(int m) {
+ return umask(m);
+}
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define dso_local i32 @call_umask(
+// CHECK-SAME: i32 noundef [[M:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = call preserve_mostcc i32 @umask.inline(i32 noundef [[TMP0:%.*]]) #[[ATTR3:[0-9]+]]
+//
+//
+// CHECK: Function Attrs: alwaysinline nounwind
+// CHECK-LABEL: define internal i32 @umask.inline(
+// CHECK-SAME: i32 [[M:%.*]]) #[[ATTR2:[0-9]+]] {
>From b8715fe8cf912ef00fb3874bce31d99fd9d0ed2a Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Wed, 21 Oct 2026 16:31:42 -0700
Subject: [PATCH 2/2] reorder stack and squash fixups
Created using spr 2.0.0-beta.1
---
.../CodeGen/strlen-inline-builtin-dllexport.c | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 clang/test/CodeGen/strlen-inline-builtin-dllexport.c
diff --git a/clang/test/CodeGen/strlen-inline-builtin-dllexport.c b/clang/test/CodeGen/strlen-inline-builtin-dllexport.c
new file mode 100644
index 0000000000000..059a43cdd16e1
--- /dev/null
+++ b/clang/test/CodeGen/strlen-inline-builtin-dllexport.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -DDLLEXPORT='__attribute__((dllexport))' -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -mdefault-visibility-export-mapping=all -DDLLEXPORT= -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+//
+// The `.inline` clone of an inline builtin has internal linkage, so it must
+// not get a DLL storage class even if the declaration is dllexport.
+
+typedef __SIZE_TYPE__ size_t;
+
+size_t strlen(const char *s);
+
+extern inline __attribute__((always_inline)) __attribute__((gnu_inline))
+DLLEXPORT size_t strlen(const char *s) {
+ return 0;
+}
+
+size_t call_strlen(const char *s) {
+ return strlen(s);
+}
+
+// CHECK-LABEL: define {{.*}}i64 @call_strlen(
+// CHECK: call i64 @strlen.inline(
+//
+// CHECK: declare {{.*}}i64 @strlen(
+//
+// CHECK-LABEL: define internal i64 @strlen.inline(
More information about the cfe-commits
mailing list