================
@@ -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

Reply via email to