================
@@ -0,0 +1,641 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o
%t-cir.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVMCIR --input-file=%t-cir.ll %s
+// RUN: FileCheck --check-prefix=NOMOVE --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=NOMOVE --input-file=%t.ll %s
+
+typedef long double ld1 __attribute__((vector_size(16)));
+
+union H {
+ struct {
+ char a;
+ int b;
+ } s;
+ int c[2];
+};
+
+union U {
+ long double ld;
+ __int128 i;
+};
+
+union U2 {
+ long double ld;
+ struct {
+ unsigned long n;
+ const char *p;
+ } v;
+};
+
+union V {
+ ld1 v;
+ long double ld;
+};
+
+union VI {
+ ld1 v;
+ long l;
+};
+
+union C {
+ _Complex long double c;
+ long double ld;
+};
+
+union M {
+ long double ld;
+ char buf[32];
+};
+
+struct S16 {
+ int a, b, c, d;
+};
+
+// CIR-DAG: !rec_H = !cir.union<"H" {data !rec_anon2E0, data !cir.array<!s32i
x 2>}>
+// CIR-DAG: !rec_U = !cir.union<"U" {data !cir.long_double<!cir.f80>, data
!s128i}>
+// CIR-DAG: !rec_U2 = !cir.union<"U2" {data !cir.long_double<!cir.f80>, data
!rec_anon2E1}>
+// CIR-DAG: !rec_V = !cir.union<"V" {data !cir.vector<1 x
!cir.long_double<!cir.f80>>, data !cir.long_double<!cir.f80>}>
+// CIR-DAG: !rec_VI = !cir.union<"VI" {data !cir.vector<1 x
!cir.long_double<!cir.f80>>, data !s64i}>
+// CIR-DAG: !rec_C = !cir.union<"C" {data
!cir.complex<!cir.long_double<!cir.f80>>, data !cir.long_double<!cir.f80>}>
+// CIR-DAG: !rec_M = !cir.union<"M" {data !cir.long_double<!cir.f80>, data
!cir.array<!s8i x 32>}, padding = {!cir.array<!u8i x 16>}>
+// CIR-DAG: !rec_anon_struct = !cir.struct<{data !u64i, data !u64i}>
+// CIR-DAG: !rec_anon_struct1 = !cir.struct<{data !u64i, data !cir.double}>
+// CIR-DAG: !rec_S16 = !cir.struct<"S16" {data !s32i, data !s32i, data !s32i,
data !s32i}>
+
+// LLVM-DAG: %union.H = type { %struct.anon{{(\.[0-9]+)?}} }
+// LLVM-DAG: %union.U = type { x86_fp80 }
+// LLVM-DAG: %union.U2 = type { x86_fp80 }
+// LLVM-DAG: %union.V = type { <1 x x86_fp80> }
+// LLVM-DAG: %union.VI = type { <1 x x86_fp80> }
+// LLVM-DAG: %union.C = type { { x86_fp80, x86_fp80 } }
+// LLVM-DAG: %union.M = type { x86_fp80, [16 x i8] }
+// LLVM-DAG: %struct.S16 = type { i32, i32, i32, i32 }
+
+// The storage type of H is a struct with padding after s.a.
+union H retH(const union H *p) { return *p; }
+
+// CIR-LABEL: cir.func {{.*}} @retH(%arg0: !cir.ptr<!rec_H> {llvm.noundef}
loc({{[^)]+}})) -> !u64i
+// CIR: %[[RETVAL:.+]] = cir.alloca "__retval" align(4) : !cir.ptr<!rec_H>
+// CIR: cir.copy %{{[^ ]+}} align(4) to %[[RETVAL]] align(4) :
!cir.ptr<!rec_H>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[RETVAL]] : !cir.ptr<!rec_H> ->
!cir.ptr<!u64i>
+// CIR: %[[RET:.+]] = cir.load align(4) %[[VIEW]] : !cir.ptr<!u64i>, !u64i
+// CIR: cir.return %[[RET]] : !u64i
+
+// LLVM-LABEL: define dso_local i64 @retH(ptr noundef %{{[^,)]+}})
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{[^,)]+}}, ptr align
4 %{{[^,)]+}}, i64 8, i1 false)
+// LLVM: %[[RET:.+]] = load i64, ptr %{{[^,)]+}}, align 4
+// LLVM: ret i64 %[[RET]]
+
+// NOMOVE-LABEL: define {{.*}}@retH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+int takeH(union H h) { return h.c[0]; }
+
+// CIR-LABEL: cir.func {{.*}} @takeH(%arg0: !u64i loc({{[^)]+}})) -> !s32i
+// CIR: %[[SLOT:.+]] = cir.alloca "coerce" align(8) : !cir.ptr<!u64i>
+// CIR: cir.store %arg0, %[[SLOT]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[SLOT]] : !cir.ptr<!u64i> ->
!cir.ptr<!rec_H>
+// CIR: %[[H:.+]] = cir.alloca "h" align(4) init : !cir.ptr<!rec_H>
+// CIR: cir.copy %[[VIEW]] align(8) to %[[H]] align(4) : !cir.ptr<!rec_H>
+
+// LLVM-LABEL: define dso_local i32 @takeH(i64 %{{[^,)]+}})
+
+// NOMOVE-LABEL: define {{.*}}@takeH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+int bindH(const union H *p) {
+ union H d = retH(p);
+ return d.c[0];
+}
+
+// CIR-LABEL: cir.func {{.*}} @bindH(%arg0: !cir.ptr<!rec_H> {llvm.noundef}
loc({{[^)]+}})) -> !s32i
+// CIR: %[[SLOT:.+]] = cir.alloca "coerce" align(8) : !cir.ptr<!u64i>
+// CIR: %[[D:.+]] = cir.alloca "d" align(4) init : !cir.ptr<!rec_H>
+// CIR: %[[RES:.+]] = cir.call @retH(%{{[^)]+}}) : (!cir.ptr<!rec_H>
{llvm.noundef}) -> !u64i
+// CIR: cir.store %[[RES]], %[[SLOT]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[SLOT]] : !cir.ptr<!u64i> ->
!cir.ptr<!rec_H>
+// CIR: cir.copy %[[VIEW]] align(8) to %[[D]] align(4) : !cir.ptr<!rec_H>
+
+// LLVM-LABEL: define dso_local i32 @bindH(ptr noundef %{{[^,)]+}})
+// LLVM: call i64 @retH(ptr noundef %{{[^,)]+}})
+
+// NOMOVE-LABEL: define {{.*}}@bindH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+void storeH(union H *q, const union H *p) { *q = retH(p); }
+
+// CIR-LABEL: cir.func {{.*}} @storeH(%arg0: !cir.ptr<!rec_H> {llvm.noundef}
loc({{[^)]+}}), %arg1: !cir.ptr<!rec_H> {llvm.noundef} loc({{[^)]+}}))
+// CIR: %[[SLOT:.+]] = cir.alloca "coerce" align(8) : !cir.ptr<!u64i>
+// CIR: %[[Q:.+]] = cir.load deref align(8) %{{[^ ]+}} :
!cir.ptr<!cir.ptr<!rec_H>>, !cir.ptr<!rec_H>
+// CIR: %[[RES:.+]] = cir.call @retH(%{{[^)]+}}) : (!cir.ptr<!rec_H>
{llvm.noundef}) -> !u64i
+// CIR: cir.store %[[RES]], %[[SLOT]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[SLOT]] : !cir.ptr<!u64i> ->
!cir.ptr<!rec_H>
+// CIR: cir.copy %[[VIEW]] align(8) to %[[Q]] align(4) : !cir.ptr<!rec_H>
+
+// LLVM-LABEL: define dso_local void @storeH(ptr noundef %{{[^,)]+}}, ptr
noundef %{{[^,)]+}})
+// LLVM: call i64 @retH(ptr noundef %{{[^,)]+}})
+
+// NOMOVE-LABEL: define {{.*}}@storeH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+int passH(const union H *p) { return takeH(*p); }
+
+// CIR-LABEL: cir.func {{.*}} @passH(%arg0: !cir.ptr<!rec_H> {llvm.noundef}
loc({{[^)]+}})) -> !s32i
+// CIR: %[[TMP:.+]] = cir.alloca "coerce" align(8) : !cir.ptr<!rec_H>
+// CIR: cir.copy %{{[^ ]+}} align(4) to %[[TMP]] align(8) : !cir.ptr<!rec_H>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[TMP]] : !cir.ptr<!rec_H> ->
!cir.ptr<!u64i>
+// CIR: %[[ARG:.+]] = cir.load align(8) %[[VIEW]] : !cir.ptr<!u64i>, !u64i
+// CIR: cir.call @takeH(%[[ARG]]) : (!u64i) -> !s32i
+
+// LLVM-LABEL: define dso_local i32 @passH(ptr noundef %{{[^,)]+}})
+// LLVM: call i32 @takeH(i64 %{{[^,)]+}})
+
+// NOMOVE-LABEL: define {{.*}}@passH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+union H vaH(int n, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, n);
+ union H h = __builtin_va_arg(ap, union H);
+ __builtin_va_end(ap);
+ return h;
+}
+
+// CIR-LABEL: cir.func {{.*}} @vaH(%arg0: !s32i {llvm.noundef} loc({{[^)]+}}),
...) -> !u64i
+// CIR: %[[RETVAL:.+]] = cir.alloca "__retval" align(4) init :
!cir.ptr<!rec_H>
+// CIR: %[[TMP:.+]] = cir.alloca "vaarg.tmp" align(4) : !cir.ptr<!rec_H>
+// CIR: %[[ADDR:.+]] = cir.ternary(
+// CIR: %[[SRC:.+]] = cir.cast bitcast %[[ADDR]] : !cir.ptr<!u8i> ->
!cir.ptr<!rec_H>
+// CIR: cir.copy %[[SRC]] align(4) to %[[TMP]] align(4) : !cir.ptr<!rec_H>
+// CIR: cir.copy %[[TMP]] align(4) to %[[RETVAL]] align(4) : !cir.ptr<!rec_H>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[RETVAL]] : !cir.ptr<!rec_H> ->
!cir.ptr<!u64i>
+// CIR: %[[RET:.+]] = cir.load align(4) %[[VIEW]] : !cir.ptr<!u64i>, !u64i
+// CIR: cir.return %[[RET]] : !u64i
+
+// LLVM-LABEL: define dso_local i64 @vaH(i32 noundef %{{[^,)]+}}, ...)
+// LLVM: icmp ule i32 %{{.+}}, 40
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{[^,)]+}}, ptr align
4 %{{[^,)]+}}, i64 8, i1 false)
+
+// NOMOVE-LABEL: define {{.*}}@vaH(
+// NOMOVE-NOT: {{(load|store)( volatile| atomic)* (x86_fp80|<[0-9]+ x
x86_fp80>|<?\{ ?x86_fp80|%struct\.|%union\.)}}
+
+// The storage type of U is a long double that stores 10 of its 16 bytes.
+union U retU(const union U *p) { return *p; }
+
+// CIR-LABEL: cir.func {{.*}} @retU(%arg0: !cir.ptr<!rec_U> {llvm.noundef}
loc({{[^)]+}})) -> !s128i
+// CIR: %[[RETVAL:.+]] = cir.alloca "__retval" align(16) : !cir.ptr<!rec_U>
+// CIR: cir.copy %{{[^ ]+}} align(16) to %[[RETVAL]] align(16) :
!cir.ptr<!rec_U>
+// CIR: %[[VIEW:.+]] = cir.cast bitcast %[[RETVAL]] : !cir.ptr<!rec_U> ->
!cir.ptr<!s128i>
+// CIR: %[[RET:.+]] = cir.load align(16) %[[VIEW]] : !cir.ptr<!s128i>, !s128i
+// CIR: cir.return %[[RET]] : !s128i
+
+// LLVMCIR-LABEL: define dso_local i128 @retU(ptr noundef %{{[^,)]+}})
----------------
adams381 wrote:
Same cause as the `takeU` comment. The ABI library's union reduction picks
`i128` for this union, where classic returns `{ i64, i64 }`. The follow-up
fixes both.
https://github.com/llvm/llvm-project/pull/231663
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits