https://github.com/adams381 created https://github.com/llvm/llvm-project/pull/191259
Add three test files for CIR ABI parity on x86_64, all with CIR/LLVM/OGCG checks: - uncopyable-args.cpp — 24 functions covering non-copyable and move-only types (trivial, default-ctor, move-ctor, etc.) - x86_64-arguments.cpp — 26 functions covering C++ struct passing, inheritance, member pointers, empty bases, packed structs - attr-noundef.cpp — 26 functions covering noundef placement on structs, unions, vectors, member pointers, _BitInt Made with [Cursor](https://cursor.com) >From 11bd7ed20226d83c57bcfc8a89aa2aef5e6d75b4 Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Wed, 8 Apr 2026 10:45:17 -0700 Subject: [PATCH 1/3] [CIR] Add uncopyable-args.cpp test for non-copyable/move-only types Port all 16 namespaces (24 functions) from CodeGenCXX/uncopyable-args.cpp to CIR/CodeGenCXX with CIR/LLVM/OGCG checks. Tests trivial, default-ctor, move-ctor, all-deleted, implicitly-deleted, one-deleted, copy-defaulted, move-defaulted, trivial-defaulted, two-copy-ctors, definition-only, deleted-by-member/base, explicit-delete, and implicitly-deleted-copy-ctor (A-F) type handling. --- clang/test/CIR/CodeGenCXX/uncopyable-args.cpp | 464 ++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 clang/test/CIR/CodeGenCXX/uncopyable-args.cpp diff --git a/clang/test/CIR/CodeGenCXX/uncopyable-args.cpp b/clang/test/CIR/CodeGenCXX/uncopyable-args.cpp new file mode 100644 index 0000000000000..48e954d9e72f3 --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/uncopyable-args.cpp @@ -0,0 +1,464 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// All test cases from CodeGenCXX/uncopyable-args.cpp (Itanium x86_64 only). +// Tests CIRGen handling of types with deleted/defaulted/implicit copy/move ctors. + +namespace trivial { +struct A { + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN7trivial3barEv +// CIR: cir.call @_ZN7trivial3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN7trivial3barEv( +// LLVM: call void @_ZN7trivial3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN7trivial3barEv( +// OGCG: call void @_ZN7trivial3fooENS_1AE(ptr +} + +namespace default_ctor { +struct A { + A(); + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN12default_ctor3barEv +// CIR: cir.call @_ZN12default_ctor1AC1Ev +// CIR: cir.call @_ZN12default_ctor3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN12default_ctor3barEv( +// LLVM: call void @_ZN12default_ctor1AC1Ev( +// LLVM: call void @_ZN12default_ctor3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN12default_ctor3barEv( +// OGCG: call {{.*}} @_ZN12default_ctor1AC1Ev( +// OGCG: call void @_ZN12default_ctor3fooENS_1AE(ptr +} + +namespace move_ctor { +struct A { + A(); + A(A &&o); + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN9move_ctor3barEv +// CIR: cir.call @_ZN9move_ctor1AC1Ev +// CIR: cir.call @_ZN9move_ctor3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN9move_ctor3barEv( +// LLVM: call void @_ZN9move_ctor1AC1Ev( +// LLVM: call void @_ZN9move_ctor3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN9move_ctor3barEv( +// OGCG: call {{.*}} @_ZN9move_ctor1AC1Ev( +// OGCG: call void @_ZN9move_ctor3fooENS_1AE(ptr noundef dead_on_return +} + +namespace all_deleted { +struct A { + A(); + A(const A &o) = delete; + A(A &&o) = delete; + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN11all_deleted3barEv +// CIR: cir.call @_ZN11all_deleted1AC1Ev +// CIR: cir.call @_ZN11all_deleted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN11all_deleted3barEv( +// LLVM: call void @_ZN11all_deleted1AC1Ev( +// LLVM: call void @_ZN11all_deleted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN11all_deleted3barEv( +// OGCG: call {{.*}} @_ZN11all_deleted1AC1Ev( +// OGCG: call void @_ZN11all_deleted3fooENS_1AE(ptr noundef dead_on_return +} + +namespace implicitly_deleted { +struct A { + A(); + A &operator=(A &&o); + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN18implicitly_deleted3barEv +// CIR: cir.call @_ZN18implicitly_deleted1AC1Ev +// CIR: cir.call @_ZN18implicitly_deleted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN18implicitly_deleted3barEv( +// LLVM: call void @_ZN18implicitly_deleted1AC1Ev( +// LLVM: call void @_ZN18implicitly_deleted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN18implicitly_deleted3barEv( +// OGCG: call {{.*}} @_ZN18implicitly_deleted1AC1Ev( +// OGCG: call void @_ZN18implicitly_deleted3fooENS_1AE(ptr noundef dead_on_return +} + +namespace one_deleted { +struct A { + A(); + A(A &&o) = delete; + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN11one_deleted3barEv +// CIR: cir.call @_ZN11one_deleted1AC1Ev +// CIR: cir.call @_ZN11one_deleted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN11one_deleted3barEv( +// LLVM: call void @_ZN11one_deleted1AC1Ev( +// LLVM: call void @_ZN11one_deleted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN11one_deleted3barEv( +// OGCG: call {{.*}} @_ZN11one_deleted1AC1Ev( +// OGCG: call void @_ZN11one_deleted3fooENS_1AE(ptr noundef dead_on_return +} + +namespace copy_defaulted { +struct A { + A(); + A(const A &o) = default; + A(A &&o) = delete; + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN14copy_defaulted3barEv +// CIR: cir.call @_ZN14copy_defaulted1AC1Ev +// CIR: cir.call @_ZN14copy_defaulted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN14copy_defaulted3barEv( +// LLVM: call void @_ZN14copy_defaulted1AC1Ev( +// LLVM: call void @_ZN14copy_defaulted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN14copy_defaulted3barEv( +// OGCG: call {{.*}} @_ZN14copy_defaulted1AC1Ev( +// OGCG: call void @_ZN14copy_defaulted3fooENS_1AE(ptr +} + +namespace move_defaulted { +struct A { + A(); + A(const A &o) = delete; + A(A &&o) = default; + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN14move_defaulted3barEv +// CIR: cir.call @_ZN14move_defaulted1AC1Ev +// CIR: cir.call @_ZN14move_defaulted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN14move_defaulted3barEv( +// LLVM: call void @_ZN14move_defaulted1AC1Ev( +// LLVM: call void @_ZN14move_defaulted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN14move_defaulted3barEv( +// OGCG: call {{.*}} @_ZN14move_defaulted1AC1Ev( +// OGCG: call void @_ZN14move_defaulted3fooENS_1AE(ptr +} + +namespace trivial_defaulted { +struct A { + A(); + A(const A &o) = default; + void *p; +}; +void foo(A); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN17trivial_defaulted3barEv +// CIR: cir.call @_ZN17trivial_defaulted1AC1Ev +// CIR: cir.call @_ZN17trivial_defaulted3fooENS_1AE + +// LLVM-LABEL: define {{.*}} void @_ZN17trivial_defaulted3barEv( +// LLVM: call void @_ZN17trivial_defaulted1AC1Ev( +// LLVM: call void @_ZN17trivial_defaulted3fooENS_1AE( + +// OGCG-LABEL: define {{.*}} void @_ZN17trivial_defaulted3barEv( +// OGCG: call {{.*}} @_ZN17trivial_defaulted1AC1Ev( +// OGCG: call void @_ZN17trivial_defaulted3fooENS_1AE(ptr +} + +namespace two_copy_ctors { +struct A { + A(); + A(const A &) = default; + A(const A &, int = 0); + void *p; +}; +struct B : A {}; + +void foo(B); +void bar() { + foo({}); +} +// CIR-LABEL: cir.func {{.*}} @_ZN14two_copy_ctors3barEv +// CIR: cir.call @{{.*}}C1Ev +// CIR: cir.call @_ZN14two_copy_ctors3fooENS_1BE + +// LLVM-LABEL: define {{.*}} void @_ZN14two_copy_ctors3barEv( +// LLVM: call void @{{.*}}C1Ev( +// LLVM: call void @_ZN14two_copy_ctors3fooENS_1BE( + +// OGCG-LABEL: define {{.*}} void @_ZN14two_copy_ctors3barEv( +// OGCG: call {{.*}} @{{.*}}C1Ev( +// OGCG: call void @_ZN14two_copy_ctors3fooENS_1BE(ptr noundef dead_on_return +} + +namespace definition_only { +struct A { + A(); + A(A &&o); + void *p; +}; +void *foo(A a) { return a.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN15definition_only3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN15definition_only3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN15definition_only3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace deleted_by_member { +struct B { + B(); + B(B &&o); + void *p; +}; +struct A { + A(); + B b; +}; +void *foo(A a) { return a.b.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN17deleted_by_member3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN17deleted_by_member3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN17deleted_by_member3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace deleted_by_base { +struct B { + B(); + B(B &&o); + void *p; +}; +struct A : B { + A(); +}; +void *foo(A a) { return a.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN15deleted_by_base3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN15deleted_by_base3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN15deleted_by_base3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace deleted_by_member_copy { +struct B { + B(); + B(const B &o) = delete; + void *p; +}; +struct A { + A(); + B b; +}; +void *foo(A a) { return a.b.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN22deleted_by_member_copy3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN22deleted_by_member_copy3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN22deleted_by_member_copy3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace deleted_by_base_copy { +struct B { + B(); + B(const B &o) = delete; + void *p; +}; +struct A : B { + A(); +}; +void *foo(A a) { return a.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN20deleted_by_base_copy3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN20deleted_by_base_copy3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN20deleted_by_base_copy3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace explicit_delete { +struct A { + A(); + A(const A &o) = delete; + void *p; +}; +void *foo(A a) { return a.p; } + +// CIR-LABEL: cir.func {{.*}} @_ZN15explicit_delete3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN15explicit_delete3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} ptr @_ZN15explicit_delete3fooENS_1AE(ptr +// OGCG: ret ptr +} + +namespace implicitly_deleted_copy_ctor { +struct A { + A &operator=(const A&); + int &&ref; +}; +int &foo(A a) { return a.ref; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(ptr +// OGCG: ret ptr + +struct B { + B &operator=(const B&); + int &ref; +}; +int &foo(B b) { return b.ref; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(ptr +// OGCG: ret ptr + +struct X { X(const X&); }; +struct Y { Y(const Y&) = default; }; + +union C { + C &operator=(const C&); + X x; + int n; +}; +int foo(C c) { return c.n; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(ptr +// OGCG: ret i32 + +struct D { + D &operator=(const D&); + union { + X x; + int n; + }; +}; +int foo(D d) { return d.n; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(ptr +// OGCG: ret i32 + +union E { + E &operator=(const E&); + Y y; + int n; +}; +int foo(E e) { return e.n; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} i32 @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32 +// OGCG: ret i32 + +struct F { + F &operator=(const F&); + union { + Y y; + int n; + }; +}; +int foo(F f) { return f.n; } + +// CIR-LABEL: cir.func {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE +// CIR: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE( +// LLVM: ret + +// OGCG-LABEL: define {{.*}} i32 @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32 +// OGCG: ret i32 +} >From 35a5b0ddd5d091dd4b41e46b4eef9fc2dc95b047 Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Wed, 8 Apr 2026 11:13:32 -0700 Subject: [PATCH 2/3] [CIR] Add x86_64-arguments.cpp C++ ABI test Port all 26 functions from CodeGenCXX/x86_64-arguments.cpp to CIR/CodeGenCXX with CIR/LLVM/OGCG checks. Tests inheritance, member pointers, empty bases, packed structs, non-trivially- destructible types, byval/sret, and union coercion on x86_64. --- .../test/CIR/CodeGenCXX/x86_64-arguments.cpp | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 clang/test/CIR/CodeGenCXX/x86_64-arguments.cpp diff --git a/clang/test/CIR/CodeGenCXX/x86_64-arguments.cpp b/clang/test/CIR/CodeGenCXX/x86_64-arguments.cpp new file mode 100644 index 0000000000000..f6267f05d2bc7 --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/x86_64-arguments.cpp @@ -0,0 +1,252 @@ +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-unknown -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-unknown -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-unknown -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// All cases from CodeGenCXX/x86_64-arguments.cpp (Itanium x86_64 only). +// Tests C++ struct passing with inheritance, member pointers, empty bases, +// packed structs, non-trivially-destructible types, and unions. + +// Basic base class test. +struct f0_s0 { unsigned a; }; +struct f0_s1 : public f0_s0 { void *b; }; +void f0(f0_s1 a0) { } + +// CIR-LABEL: cir.func {{.*}} @_Z2f05f0_s1 +// LLVM-LABEL: define {{.*}} void @_Z2f05f0_s1( +// OGCG-LABEL: define {{.*}} void @_Z2f05f0_s1(i32 %a0.coerce0, ptr %a0.coerce1) + +// Two eight-bytes in base class. +struct f1_s0 { unsigned a; unsigned b; float c; }; +struct f1_s1 : public f1_s0 { float d;}; +void f1(f1_s1 a0) { } + +// CIR-LABEL: cir.func {{.*}} @_Z2f15f1_s1 +// LLVM-LABEL: define {{.*}} void @_Z2f15f1_s1( +// OGCG-LABEL: define {{.*}} void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1) + +// Two eight-bytes in base class and merge. +struct f2_s0 { unsigned a; unsigned b; float c; }; +struct f2_s1 : public f2_s0 { char d;}; +void f2(f2_s1 a0) { } + +// CIR-LABEL: cir.func {{.*}} @_Z2f25f2_s1 +// LLVM-LABEL: define {{.*}} void @_Z2f25f2_s1( +// OGCG-LABEL: define {{.*}} void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1) + +// PR5831 +struct s3_0 {}; +struct s3_1 { struct s3_0 a; long b; }; +void f3(struct s3_1 x) {} + +// CIR-LABEL: cir.func {{.*}} @_Z2f34s3_1 +// LLVM-LABEL: define {{.*}} void @_Z2f34s3_1( +// OGCG-LABEL: define {{.*}} void @_Z2f34s3_1(i64 %x.coerce) + +// Member data pointer and member function pointer. +struct s4 {}; +typedef int s4::* s4_mdp; +typedef int (s4::*s4_mfp)(); +s4_mdp f4_0(s4_mdp a) { return a; } +s4_mfp f4_1(s4_mfp a) { return a; } + +// CIR-LABEL: cir.func {{.*}} @_Z4f4_0M2s4i +// CIR-LABEL: cir.func {{.*}} @_Z4f4_1M2s4FivE + +// LLVM-LABEL: define {{.*}} i64 @_Z4f4_0M2s4i(i64 +// LLVM-LABEL: define {{.*}} @_Z4f4_1M2s4FivE( + +// OGCG-LABEL: define {{.*}} i64 @_Z4f4_0M2s4i(i64 %a) +// OGCG: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1) + +// Struct with member data pointer (fits in registers). +struct struct_with_mdp { char *a; s4_mdp b; }; +void f_struct_with_mdp(struct_with_mdp a) { (void)a; } + +// CIR-LABEL: cir.func {{.*}} @_Z17f_struct_with_mdp +// LLVM-LABEL: define {{.*}} void @_Z17f_struct_with_mdp +// OGCG-LABEL: define {{.*}} void @{{.*}}f_struct_with_mdp{{.*}}(ptr %a.coerce0, i64 %a.coerce1) + +// Struct with member function pointer (too big, goes to memory). +struct struct_with_mfp_0 { char a; s4_mfp b; }; +void f_struct_with_mfp_0(struct_with_mfp_0 a) { (void)a; } + +// CIR-LABEL: cir.func {{.*}} @_Z19f_struct_with_mfp_0 +// LLVM-LABEL: define {{.*}} void @_Z19f_struct_with_mfp_0 +// OGCG-LABEL: define {{.*}} void @{{.*}}f_struct_with_mfp_0{{.*}}(ptr byval(%struct{{.*}}) align 8 %a) + +struct struct_with_mfp_1 { void *a; s4_mfp b; }; +void f_struct_with_mfp_1(struct_with_mfp_1 a) { (void)a; } + +// CIR-LABEL: cir.func {{.*}} @_Z19f_struct_with_mfp_1 +// LLVM-LABEL: define {{.*}} void @_Z19f_struct_with_mfp_1 +// OGCG-LABEL: define {{.*}} void @{{.*}}f_struct_with_mfp_1{{.*}}(ptr byval(%struct{{.*}}) align 8 %a) + +namespace PR7523 { +struct StringRef { char *a; }; +void AddKeyword(StringRef, int x); +void foo() { + AddKeyword(StringRef(), 4); +} +} + +// CIR-LABEL: cir.func {{.*}} @_ZN6PR75233fooEv +// CIR: cir.call @_ZN6PR752310AddKeywordENS_9StringRefEi + +// LLVM-LABEL: define {{.*}} void @_ZN6PR75233fooEv( +// LLVM: call void @_ZN6PR752310AddKeywordENS_9StringRefEi( + +// OGCG-LABEL: define {{.*}} void @_ZN6PR75233fooEv( +// OGCG: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(ptr {{.*}}, i32 4) + +namespace PR7742 { + struct s2 { float a[2]; }; + struct c2 : public s2 {}; + c2 foo(c2 *P) { return c2(); } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN6PR77423fooEPNS_2c2E +// LLVM-LABEL: define {{.*}} @_ZN6PR77423fooEPNS_2c2E( +// OGCG-LABEL: define {{.*}} <2 x float> @_ZN6PR77423fooEPNS_2c2E(ptr %P) + +namespace PR5179 { + struct B {}; + struct B1 : B { int* pa; }; + struct B2 : B { B1 b1; }; + const void *bar(B2 b2) { return b2.b1.pa; } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN6PR51793barENS_2B2E +// LLVM-LABEL: define {{.*}} @_ZN6PR51793barENS_2B2E( +// OGCG-LABEL: define {{.*}} ptr @_ZN6PR51793barENS_2B2E(ptr %b2.coerce) + +namespace test5 { + struct Xbase { }; + struct Empty { }; + struct Y; + struct X : public Xbase { Empty empty; Y f(); }; + struct Y : public X { Empty empty; }; + X getX(); + int takeY(const Y&, int y); + void g() { takeY(getX().f(), 42); } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN5test51gEv +// CIR: cir.alloca !rec_{{.*}}Y +// CIR: cir.alloca !rec_{{.*}}X +// CIR: cir.call @_ZN5test54getXEv +// CIR: cir.call @_ZN5test51X1fEv +// CIR: cir.call @_ZN5test55takeYERKNS_1YEi + +// LLVM-LABEL: define {{.*}} void @_ZN5test51gEv( +// LLVM: alloca %"struct.test5::Y" +// LLVM: alloca %"struct.test5::X" + +// OGCG: void @_ZN5test51gEv() +// OGCG: alloca %"struct.test5::Y" +// OGCG: alloca %"struct.test5::X" +// OGCG: alloca %"struct.test5::Y" + +namespace test6 { + struct outer { int x; struct epsilon_matcher {} e; int f; }; + int test(outer x) { return x.x + x.f; } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN5test64testENS_5outerE +// LLVM-LABEL: define {{.*}} i32 @_ZN5test64testENS_5outerE( +// OGCG-LABEL: define {{.*}} i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) + +namespace test7 { + struct StringRef {char* ptr; long len; }; + class A { public: ~A(); }; + A x(A, A, long, long, StringRef) { return A(); } + A y(A, long double, long, long, StringRef) { return A(); } + struct StringDouble {char * ptr; double d;}; + A z(A, A, A, A, A, StringDouble) { return A(); } + A zz(A, A, A, A, StringDouble) { return A(); } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN5test71xENS_1AES0_llNS_9StringRefE +// CIR-LABEL: cir.func {{.*}} @_ZN5test71yENS_1AEellNS_9StringRefE +// CIR-LABEL: cir.func {{.*}} @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE +// CIR-LABEL: cir.func {{.*}} @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE + +// LLVM-LABEL: define {{.*}} @_ZN5test71xENS_1AES0_llNS_9StringRefE( +// LLVM-LABEL: define {{.*}} @_ZN5test71yENS_1AEellNS_9StringRefE( +// LLVM-LABEL: define {{.*}} @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE( +// LLVM-LABEL: define {{.*}} @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE( + +// OGCG: define{{.*}} void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval({{.*}}) align 8 {{%.*}}) +// OGCG: define{{.*}} void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} ptr +// OGCG: define{{.*}} void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval({{.*}}) align 8 {{%.*}}) +// OGCG: define{{.*}} void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} ptr + +namespace test8 { + class A { char big[17]; }; + class B : public A {}; + void foo(B b); + void bar() { B b; foo(b); } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN5test83barEv +// CIR: cir.call @_ZN5test83fooENS_1BE + +// LLVM-LABEL: define {{.*}} void @_ZN5test83barEv( +// LLVM: call void @_ZN5test83fooENS_1BE( + +// OGCG-LABEL: define {{.*}} void @_ZN5test83barEv( +// OGCG: call void @_ZN5test83fooENS_1BE(ptr byval(%"class.test8::B") align 8 + +namespace test9 { + struct S { void *data[3]; }; + struct T { void *data[2]; }; + void foo(S*, T*) {} + S a(int, int, int, int, T, void*) { return S(); } + S* b(S* sret, int, int, int, int, T, void*) { return sret; } + S c(int, int, int, T, void*) { return S(); } + S* d(S* sret, int, int, int, T, void*) { return sret; } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN5test93fooEPNS_1SEPNS_1TE +// CIR-LABEL: cir.func {{.*}} @_ZN5test91aEiiiiNS_1TEPv +// CIR-LABEL: cir.func {{.*}} @_ZN5test91bEPNS_1SEiiiiNS_1TEPv +// CIR-LABEL: cir.func {{.*}} @_ZN5test91cEiiiNS_1TEPv +// CIR-LABEL: cir.func {{.*}} @_ZN5test91dEPNS_1SEiiiNS_1TEPv + +// LLVM-LABEL: define {{.*}} void @_ZN5test93fooEPNS_1SEPNS_1TE(ptr {{.*}}, ptr +// LLVM-LABEL: define {{.*}} @_ZN5test91aEiiiiNS_1TEPv( +// LLVM-LABEL: define {{.*}} ptr @_ZN5test91bEPNS_1SEiiiiNS_1TEPv( +// LLVM-LABEL: define {{.*}} @_ZN5test91cEiiiNS_1TEPv( +// LLVM-LABEL: define {{.*}} ptr @_ZN5test91dEPNS_1SEiiiNS_1TEPv( + +// OGCG: define{{.*}} void @_ZN5test93fooEPNS_1SEPNS_1TE(ptr %0, ptr %1) +// OGCG: define{{.*}} void @_ZN5test91aEiiiiNS_1TEPv(ptr dead_on_unwind noalias writable sret({{.*}}) align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, ptr byval({{.*}}) align 8 %4, ptr %5) +// OGCG: define{{.*}} ptr @_ZN5test91bEPNS_1SEiiiiNS_1TEPv(ptr {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, ptr byval({{.*}}) align 8 %4, ptr %5) +// OGCG: define{{.*}} void @_ZN5test91cEiiiNS_1TEPv(ptr dead_on_unwind noalias writable sret({{.*}}) align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, ptr {{%.*}}, ptr {{%.*}}, ptr %3) +// OGCG: define{{.*}} ptr @_ZN5test91dEPNS_1SEiiiNS_1TEPv(ptr {{%.*}}, i32 %0, i32 %1, i32 %2, ptr {{%.*}}, ptr {{%.*}}, ptr %3) + +namespace test10 { +#pragma pack(1) +struct BasePacked { char one; short two; }; +#pragma pack() +struct DerivedPacked : public BasePacked { int three; }; +int FuncForDerivedPacked(DerivedPacked d) { return d.three; } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN6test1020FuncForDerivedPackedENS_13DerivedPackedE +// LLVM-LABEL: define {{.*}} i32 @_ZN6test1020FuncForDerivedPackedENS_13DerivedPackedE( +// OGCG-LABEL: define {{.*}} i32 @_ZN6test1020FuncForDerivedPackedENS_13DerivedPackedE(ptr byval({{.*}}) align 8 + +namespace test11 { +union U { + float f1; + char __attribute__((__vector_size__(1))) f2; +}; +int f(union U u) { return u.f2[1]; } +} + +// CIR-LABEL: cir.func {{.*}} @_ZN6test111fENS_1UE +// LLVM-LABEL: define {{.*}} i32 @_ZN6test111fENS_1UE( +// OGCG-LABEL: define {{.*}} i32 @_ZN6test111fENS_1UE(i32 >From 43ee884efabe3b7538c1c4405ac0d6fdb7a90cf9 Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Wed, 8 Apr 2026 11:28:44 -0700 Subject: [PATCH 3/3] [CIR] Add attr-noundef.cpp test for noundef attribute placement Port all 26 functions from CodeGen/attr-noundef.cpp to CIR/CodeGen with CIR/LLVM/OGCG checks (x86_64 only). Tests noundef on structs, unions, this pointers, vectors, function/array pointers, member pointers, nullptr_t, and _BitInt types. --- clang/test/CIR/CodeGen/attr-noundef.cpp | 235 ++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 clang/test/CIR/CodeGen/attr-noundef.cpp diff --git a/clang/test/CIR/CodeGen/attr-noundef.cpp b/clang/test/CIR/CodeGen/attr-noundef.cpp new file mode 100644 index 0000000000000..3d133441ad5a0 --- /dev/null +++ b/clang/test/CIR/CodeGen/attr-noundef.cpp @@ -0,0 +1,235 @@ +// RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// All cases from CodeGen/attr-noundef.cpp (x86_64 only). +// Tests noundef placement on structs, unions, this pointers, vectors, +// function/array pointers, member pointers, nullptr_t, and _BitInt. + +//************ Passing structs by value + +namespace check_structs { +struct Trivial { + int a; +}; +Trivial ret_trivial() { return {}; } +void pass_trivial(Trivial e) {} + +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs11ret_trivialEv +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs12pass_trivialENS_7TrivialE + +// LLVM-LABEL: define {{.*}} @_ZN13check_structs11ret_trivialEv( +// LLVM-LABEL: define {{.*}} void @_ZN13check_structs12pass_trivialENS_7TrivialE( + +// OGCG: define{{.*}} i32 @_ZN13check_structs11ret_trivialEv +// OGCG: define{{.*}} void @_ZN13check_structs12pass_trivialENS_7TrivialE{{.*}}(i32 % + +struct NoCopy { + int a; + NoCopy(NoCopy &) = delete; +}; +NoCopy ret_nocopy() { return {}; } +void pass_nocopy(NoCopy e) {} + +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs10ret_nocopyEv +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs11pass_nocopyENS_6NoCopyE + +// LLVM-LABEL: define {{.*}} @_ZN13check_structs10ret_nocopyEv( +// LLVM-LABEL: define {{.*}} void @_ZN13check_structs11pass_nocopyENS_6NoCopyE( + +// OGCG: define{{.*}} void @_ZN13check_structs10ret_nocopyEv{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % +// OGCG: define{{.*}} void @_ZN13check_structs11pass_nocopyENS_6NoCopyE{{.*}}(ptr noundef dead_on_return % + +struct Huge { + int a[1024]; +}; +Huge ret_huge() { return {}; } +void pass_huge(Huge h) {} + +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs8ret_hugeEv +// CIR-LABEL: cir.func {{.*}} @_ZN13check_structs9pass_hugeENS_4HugeE + +// LLVM-LABEL: define {{.*}} @_ZN13check_structs8ret_hugeEv( +// LLVM-LABEL: define {{.*}} void @_ZN13check_structs9pass_hugeENS_4HugeE( + +// OGCG: define{{.*}} void @_ZN13check_structs8ret_hugeEv{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % +// OGCG: define{{.*}} void @_ZN13check_structs9pass_hugeENS_4HugeE{{.*}}(ptr noundef +} // namespace check_structs + +//************ Passing unions by value + +namespace check_unions { +union Trivial { + int a; +}; +Trivial ret_trivial() { return {}; } +void pass_trivial(Trivial e) {} + +// CIR-LABEL: cir.func {{.*}} @_ZN12check_unions11ret_trivialEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_unions12pass_trivialENS_7TrivialE + +// LLVM-LABEL: define {{.*}} @_ZN12check_unions11ret_trivialEv( +// LLVM-LABEL: define {{.*}} void @_ZN12check_unions12pass_trivialENS_7TrivialE( + +// OGCG: define{{.*}} i32 @_ZN12check_unions11ret_trivialEv +// OGCG: define{{.*}} void @_ZN12check_unions12pass_trivialENS_7TrivialE{{.*}}(i32 % + +union NoCopy { + int a; + NoCopy(NoCopy &) = delete; +}; +NoCopy ret_nocopy() { return {}; } +void pass_nocopy(NoCopy e) {} + +// CIR-LABEL: cir.func {{.*}} @_ZN12check_unions10ret_nocopyEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_unions11pass_nocopyENS_6NoCopyE + +// LLVM-LABEL: define {{.*}} @_ZN12check_unions10ret_nocopyEv( +// LLVM-LABEL: define {{.*}} void @_ZN12check_unions11pass_nocopyENS_6NoCopyE( + +// OGCG: define{{.*}} void @_ZN12check_unions10ret_nocopyEv{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % +// OGCG: define{{.*}} void @_ZN12check_unions11pass_nocopyENS_6NoCopyE{{.*}}(ptr noundef dead_on_return % +} // namespace check_unions + +//************ Passing `this` pointers + +namespace check_this { +struct Object { + int data[]; + + Object() { + this->data[0] = 0; + } + int getData() { + return this->data[0]; + } + Object *getThis() { + return this; + } +}; + +void use_object() { + Object obj; + obj.getData(); + obj.getThis(); +} + +// CIR-LABEL: cir.func {{.*}} @_ZN10check_this10use_objectEv +// CIR: cir.call @_ZN10check_this6ObjectC1Ev +// CIR: cir.call @_ZN10check_this6Object7getDataEv +// CIR: cir.call @_ZN10check_this6Object7getThisEv + +// this pointer: noundef nonnull dereferenceable align +// LLVM: define linkonce_odr void @_ZN10check_this6Object{{.*}}(ptr noundef nonnull align 4 dereferenceable(1) % +// LLVM: define linkonce_odr noundef i32 @_ZN10check_this6Object7getDataEv(ptr noundef nonnull align 4 dereferenceable(1) % +// LLVM: define linkonce_odr noundef ptr @_ZN10check_this6Object7getThisEv(ptr noundef nonnull align 4 dereferenceable(1) % + +// OGCG: define linkonce_odr void @_ZN10check_this6ObjectC1Ev(ptr noundef nonnull align 4 dereferenceable(1) % +// OGCG: define linkonce_odr noundef i32 @_ZN10check_this6Object7getDataEv(ptr noundef nonnull align 4 dereferenceable(1) % +// OGCG: define linkonce_odr noundef ptr @_ZN10check_this6Object7getThisEv(ptr noundef nonnull align 4 dereferenceable(1) % +} // namespace check_this + +//************ Passing vector types + +namespace check_vecs { +typedef int __attribute__((vector_size(12))) i32x3; +i32x3 ret_vec() { + return {}; +} +void pass_vec(i32x3 v) { +} + +// CIR-LABEL: cir.func {{.*}} @_ZN10check_vecs7ret_vecEv +// CIR-LABEL: cir.func {{.*}} @_ZN10check_vecs8pass_vecEDv3_i + +// LLVM: define {{.*}} noundef <3 x i32> @_ZN10check_vecs7ret_vecEv( +// LLVM: define {{.*}} void @_ZN10check_vecs8pass_vecEDv3_i(<3 x i32> noundef % + +// OGCG: define {{.*}} noundef <3 x i32> @_ZN10check_vecs7ret_vecEv( +// OGCG: define {{.*}} void @_ZN10check_vecs8pass_vecEDv3_i(<3 x i32> noundef % +} // namespace check_vecs + +//************ Passing exotic types + +namespace check_exotic { +struct Object { + int mfunc(); + int mdata; +}; +typedef int Object::*mdptr; +typedef int (Object::*mfptr)(); +typedef decltype(nullptr) nullptr_t; +typedef int (*arrptr)[32]; +typedef int (*fnptr)(int); + +arrptr ret_arrptr() { + return nullptr; +} +fnptr ret_fnptr() { + return nullptr; +} +mdptr ret_mdptr() { + return nullptr; +} +mfptr ret_mfptr() { + return nullptr; +} +nullptr_t ret_npt() { + return nullptr; +} +void pass_npt(nullptr_t t) { +} +_BitInt(3) ret_BitInt() { + return 0; +} +void pass_BitInt(_BitInt(3) e) { +} +void pass_large_BitInt(_BitInt(127) e) { +} + +// Pointers to arrays/functions: always noundef +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic10ret_arrptrEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic9ret_fnptrEv + +// LLVM: define {{.*}} noundef ptr @_ZN12check_exotic10ret_arrptrEv( +// LLVM: define {{.*}} noundef ptr @_ZN12check_exotic9ret_fnptrEv( + +// OGCG: define {{.*}} noundef ptr @_ZN12check_exotic10ret_arrptrEv( +// OGCG: define {{.*}} noundef ptr @_ZN12check_exotic9ret_fnptrEv( + +// Member pointers: never noundef +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic9ret_mdptrEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic9ret_mfptrEv + +// LLVM: define {{.*}} i64 @_ZN12check_exotic9ret_mdptrEv( +// LLVM: define {{.*}} { i64, i64 } @_ZN12check_exotic9ret_mfptrEv( + +// OGCG: define {{.*}} i64 @_ZN12check_exotic9ret_mdptrEv( +// OGCG: define {{.*}} { i64, i64 } @_ZN12check_exotic9ret_mfptrEv( + +// nullptr_t: never noundef +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic7ret_nptEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic8pass_nptEDn + +// LLVM: define {{.*}} ptr @_ZN12check_exotic7ret_nptEv( +// LLVM: define {{.*}} void @_ZN12check_exotic8pass_nptEDn(ptr % + +// OGCG: define {{.*}} ptr @_ZN12check_exotic7ret_nptEv( +// OGCG: define {{.*}} void @_ZN12check_exotic8pass_nptEDn(ptr % + +// _BitInt types +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic10ret_BitIntEv +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic11pass_BitIntEDB3_ +// CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic17pass_large_BitIntEDB127_ + +// LLVM: define {{.*}} i3 @_ZN12check_exotic10ret_BitIntEv( +// LLVM: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 % +// LLVM: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i127 % + +// OGCG: define {{.*}} noundef signext i3 @_ZN12check_exotic10ret_BitIntEv( +// OGCG: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef signext % +// OGCG: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i64 noundef %{{.*}}, i64 noundef % +} // namespace check_exotic _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
