blob: 23e862b24517d76910fad875e83fd11512d13473 [file] [log] [blame]
// 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-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
union U1 {
int n;
char c;
};
// CIR: !rec_U1 = !cir.record<union "U1" {!s32i, !s8i}>
// LLVM: %union.U1 = type { i32 }
// OGCG: %union.U1 = type { i32 }
union U2 {
char b;
short s;
int i;
float f;
double d;
};
// CIR: !rec_U2 = !cir.record<union "U2" {!s8i, !s16i, !s32i, !cir.float, !cir.double}>
// LLVM: %union.U2 = type { double }
// OGCG: %union.U2 = type { double }
union U3 {
char c[5];
int i;
} __attribute__((packed));
// CIR: !rec_U3 = !cir.record<union "U3" packed padded {!cir.array<!s8i x 5>, !s32i, !u8i}>
// LLVM: %union.U3 = type <{ i32, i8 }>
// OGCG: %union.U3 = type <{ i32, i8 }>
union U4 {
char c[5];
int i;
};
// CIR: !rec_U4 = !cir.record<union "U4" padded {!cir.array<!s8i x 5>, !s32i, !cir.array<!u8i x 4>}>
// LLVM: %union.U4 = type { i32, [4 x i8] }
// OGCG: %union.U4 = type { i32, [4 x i8] }
union IncompleteU *p;
// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteU>
// LLVM: @p = global ptr null
// OGCG: @p = global ptr null, align 8
void f1(void) {
union IncompleteU *p;
}
// CIR: cir.func{{.*}} @f1()
// CIR-NEXT: cir.alloca !cir.ptr<!rec_IncompleteU>, !cir.ptr<!cir.ptr<!rec_IncompleteU>>, ["p"]
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @f1()
// LLVM-NEXT: %[[P:.*]] = alloca ptr, i64 1, align 8
// LLVM-NEXT: ret void
// OGCG: define{{.*}} void @f1()
// OGCG-NEXT: entry:
// OGCG-NEXT: %[[P:.*]] = alloca ptr, align 8
// OGCG-NEXT: ret void
int f2(void) {
union U1 u;
u.n = 42;
return u.n;
}
// CIR: cir.func{{.*}} @f2() -> !s32i
// CIR-NEXT: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
// CIR-NEXT: %[[U:.*]] = cir.alloca !rec_U1, !cir.ptr<!rec_U1>, ["u"] {alignment = 4 : i64}
// CIR-NEXT: %[[I:.*]] = cir.const #cir.int<42> : !s32i
// CIR-NEXT: %[[N:.*]] = cir.get_member %[[U]][0] {name = "n"} : !cir.ptr<!rec_U1> -> !cir.ptr<!s32i>
// CIR-NEXT: cir.store{{.*}} %[[I]], %[[N]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: %[[N2:.*]] = cir.get_member %[[U]][0] {name = "n"} : !cir.ptr<!rec_U1> -> !cir.ptr<!s32i>
// CIR-NEXT: %[[VAL:.*]] = cir.load{{.*}} %[[N2]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store{{.*}} %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.return %[[RET]] : !s32i
// LLVM: define{{.*}} i32 @f2()
// LLVM-NEXT: %[[RETVAL:.*]] = alloca i32, i64 1, align 4
// LLVM-NEXT: %[[U:.*]] = alloca %union.U1, i64 1, align 4
// LLVM-NEXT: store i32 42, ptr %[[U]], align 4
// LLVM-NEXT: %[[N_VAL:.*]] = load i32, ptr %[[U]], align 4
// LLVM-NEXT: store i32 %[[N_VAL]], ptr %[[RETVAL]], align 4
// LLVM-NEXT: %[[RET:.*]] = load i32, ptr %[[RETVAL]], align 4
// LLVM-NEXT: ret i32 %[[RET]]
// OGCG: define{{.*}} i32 @f2()
// OGCG-NEXT: entry:
// OGCG-NEXT: %[[U:.*]] = alloca %union.U1, align 4
// OGCG-NEXT: store i32 42, ptr %[[U]], align 4
// OGCG-NEXT: %[[N_VAL:.*]] = load i32, ptr %[[U]], align 4
// OGCG-NEXT: ret i32 %[[N_VAL]]
void shouldGenerateUnionAccess(union U2 u) {
u.b = 0;
u.b;
u.i = 1;
u.i;
u.f = 0.1F;
u.f;
u.d = 0.1;
u.d;
}
// CIR: cir.func{{.*}} @shouldGenerateUnionAccess(%[[ARG:.*]]: !rec_U2
// CIR-NEXT: %[[U:.*]] = cir.alloca !rec_U2, !cir.ptr<!rec_U2>, ["u", init] {alignment = 8 : i64}
// CIR-NEXT: cir.store{{.*}} %[[ARG]], %[[U]] : !rec_U2, !cir.ptr<!rec_U2>
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: %[[ZERO_CHAR:.*]] = cir.cast(integral, %[[ZERO]] : !s32i), !s8i
// CIR-NEXT: %[[B_PTR:.*]] = cir.get_member %[[U]][0] {name = "b"} : !cir.ptr<!rec_U2> -> !cir.ptr<!s8i>
// CIR-NEXT: cir.store{{.*}} %[[ZERO_CHAR]], %[[B_PTR]] : !s8i, !cir.ptr<!s8i>
// CIR-NEXT: %[[B_PTR2:.*]] = cir.get_member %[[U]][0] {name = "b"} : !cir.ptr<!rec_U2> -> !cir.ptr<!s8i>
// CIR-NEXT: %[[B_VAL:.*]] = cir.load{{.*}} %[[B_PTR2]] : !cir.ptr<!s8i>, !s8i
// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR-NEXT: %[[I_PTR:.*]] = cir.get_member %[[U]][2] {name = "i"} : !cir.ptr<!rec_U2> -> !cir.ptr<!s32i>
// CIR-NEXT: cir.store{{.*}} %[[ONE]], %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: %[[I_PTR2:.*]] = cir.get_member %[[U]][2] {name = "i"} : !cir.ptr<!rec_U2> -> !cir.ptr<!s32i>
// CIR-NEXT: %[[I_VAL:.*]] = cir.load{{.*}} %[[I_PTR2]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[FLOAT_VAL:.*]] = cir.const #cir.fp<1.000000e-01> : !cir.float
// CIR-NEXT: %[[F_PTR:.*]] = cir.get_member %[[U]][3] {name = "f"} : !cir.ptr<!rec_U2> -> !cir.ptr<!cir.float>
// CIR-NEXT: cir.store{{.*}} %[[FLOAT_VAL]], %[[F_PTR]] : !cir.float, !cir.ptr<!cir.float>
// CIR-NEXT: %[[F_PTR2:.*]] = cir.get_member %[[U]][3] {name = "f"} : !cir.ptr<!rec_U2> -> !cir.ptr<!cir.float>
// CIR-NEXT: %[[F_VAL:.*]] = cir.load{{.*}} %[[F_PTR2]] : !cir.ptr<!cir.float>, !cir.float
// CIR-NEXT: %[[DOUBLE_VAL:.*]] = cir.const #cir.fp<1.000000e-01> : !cir.double
// CIR-NEXT: %[[D_PTR:.*]] = cir.get_member %[[U]][4] {name = "d"} : !cir.ptr<!rec_U2> -> !cir.ptr<!cir.double>
// CIR-NEXT: cir.store{{.*}} %[[DOUBLE_VAL]], %[[D_PTR]] : !cir.double, !cir.ptr<!cir.double>
// CIR-NEXT: %[[D_PTR2:.*]] = cir.get_member %[[U]][4] {name = "d"} : !cir.ptr<!rec_U2> -> !cir.ptr<!cir.double>
// CIR-NEXT: %[[D_VAL:.*]] = cir.load{{.*}} %[[D_PTR2]] : !cir.ptr<!cir.double>, !cir.double
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @shouldGenerateUnionAccess(%union.U2 %[[ARG:.*]])
// LLVM-NEXT: %[[U:.*]] = alloca %union.U2, i64 1, align 8
// LLVM-NEXT: store %union.U2 %[[ARG]], ptr %[[U]], align 8
// LLVM-NEXT: store i8 0, ptr %[[U]], align 8
// LLVM-NEXT: %[[B_VAL:.*]] = load i8, ptr %[[U]], align 8
// LLVM-NEXT: store i32 1, ptr %[[U]], align 8
// LLVM-NEXT: %[[I_VAL:.*]] = load i32, ptr %[[U]], align 8
// LLVM-NEXT: store float 0x3FB99999A0000000, ptr %[[U]], align 8
// LLVM-NEXT: %[[F_VAL:.*]] = load float, ptr %[[U]], align 8
// LLVM-NEXT: store double 1.000000e-01, ptr %[[U]], align 8
// LLVM-NEXT: %[[D_VAL:.*]] = load double, ptr %[[U]], align 8
// LLVM-NEXT: ret void
// OGCG: define{{.*}} void @shouldGenerateUnionAccess(i64 %[[ARG:.*]])
// OGCG-NEXT: entry:
// OGCG-NEXT: %[[U:.*]] = alloca %union.U2, align 8
// OGCG-NEXT: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %union.U2, ptr %[[U]], i32 0, i32 0
// OGCG-NEXT: store i64 %[[ARG]], ptr %[[COERCE_DIVE]], align 8
// OGCG-NEXT: store i8 0, ptr %[[U]], align 8
// OGCG-NEXT: %[[B_VAL:.*]] = load i8, ptr %[[U]], align 8
// OGCG-NEXT: store i32 1, ptr %[[U]], align 8
// OGCG-NEXT: %[[I_VAL:.*]] = load i32, ptr %[[U]], align 8
// OGCG-NEXT: store float 0x3FB99999A0000000, ptr %[[U]], align 8
// OGCG-NEXT: %[[F_VAL:.*]] = load float, ptr %[[U]], align 8
// OGCG-NEXT: store double 1.000000e-01, ptr %[[U]], align 8
// OGCG-NEXT: %[[D_VAL:.*]] = load double, ptr %[[U]], align 8
// OGCG-NEXT: ret void
void f3(union U3 u) {
u.c[2] = 0;
}
// CIR: cir.func{{.*}} @f3(%[[ARG:.*]]: !rec_U3
// CIR-NEXT: %[[U:.*]] = cir.alloca !rec_U3, !cir.ptr<!rec_U3>, ["u", init] {alignment = 1 : i64}
// CIR-NEXT: cir.store{{.*}} %[[ARG]], %[[U]] : !rec_U3, !cir.ptr<!rec_U3>
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: %[[ZERO_CHAR:.*]] = cir.cast(integral, %[[ZERO]] : !s32i), !s8i
// CIR-NEXT: %[[IDX:.*]] = cir.const #cir.int<2> : !s32i
// CIR-NEXT: %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : !cir.ptr<!rec_U3> -> !cir.ptr<!cir.array<!s8i x 5>>
// CIR-NEXT: %[[C_DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[C_PTR]] : !cir.ptr<!cir.array<!s8i x 5>>), !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.ptr_stride(%[[C_DECAY]] : !cir.ptr<!s8i>, %[[IDX]] : !s32i), !cir.ptr<!s8i>
// CIR-NEXT: cir.store{{.*}} %[[ZERO_CHAR]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @f3(%union.U3 %[[ARG:.*]])
// LLVM-NEXT: %[[U:.*]] = alloca %union.U3, i64 1, align 1
// LLVM-NEXT: store %union.U3 %[[ARG]], ptr %[[U]], align 1
// LLVM-NEXT: %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 2
// LLVM-NEXT: store i8 0, ptr %[[ELEM_PTR]], align 1
// LLVM-NEXT: ret void
// OGCG: define{{.*}} void @f3(i40 %[[ARG:.*]])
// OGCG-NEXT: entry:
// OGCG-NEXT: %[[U:.*]] = alloca %union.U3, align 1
// OGCG-NEXT: store i40 %[[ARG]], ptr %[[U]], align 1
// OGCG-NEXT: %[[ARRAYIDX:.*]] = getelementptr inbounds [5 x i8], ptr %[[U]], i64 0, i64 2
// OGCG-NEXT: store i8 0, ptr %[[ARRAYIDX]], align 1
// OGCG-NEXT: ret void
void f5(union U4 u) {
u.c[4] = 65;
}
// CIR: cir.func{{.*}} @f5(%[[ARG:.*]]: !rec_U4
// CIR-NEXT: %[[U:.*]] = cir.alloca !rec_U4, !cir.ptr<!rec_U4>, ["u", init] {alignment = 4 : i64}
// CIR-NEXT: cir.store{{.*}} %[[ARG]], %[[U]] : !rec_U4, !cir.ptr<!rec_U4>
// CIR-NEXT: %[[CHAR_VAL:.*]] = cir.const #cir.int<65> : !s32i
// CIR-NEXT: %[[CHAR_CAST:.*]] = cir.cast(integral, %[[CHAR_VAL]] : !s32i), !s8i
// CIR-NEXT: %[[IDX:.*]] = cir.const #cir.int<4> : !s32i
// CIR-NEXT: %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : !cir.ptr<!rec_U4> -> !cir.ptr<!cir.array<!s8i x 5>>
// CIR-NEXT: %[[C_DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[C_PTR]] : !cir.ptr<!cir.array<!s8i x 5>>), !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.ptr_stride(%[[C_DECAY]] : !cir.ptr<!s8i>, %[[IDX]] : !s32i), !cir.ptr<!s8i>
// CIR-NEXT: cir.store{{.*}} %[[CHAR_CAST]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @f5(%union.U4 %[[ARG:.*]])
// LLVM-NEXT: %[[U:.*]] = alloca %union.U4, i64 1, align 4
// LLVM-NEXT: store %union.U4 %[[ARG]], ptr %[[U]], align 4
// LLVM-NEXT: %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 4
// LLVM-NEXT: store i8 65, ptr %[[ELEM_PTR]], align 4
// LLVM-NEXT: ret void
// OGCG: define{{.*}} void @f5(i64 %[[ARG:.*]])
// OGCG-NEXT: entry:
// OGCG-NEXT: %[[U:.*]] = alloca %union.U4, align 4
// OGCG-NEXT: store i64 %[[ARG]], ptr %[[U]], align 4
// OGCG-NEXT: %[[ARRAYIDX:.*]] = getelementptr inbounds [5 x i8], ptr %[[U]], i64 0, i64 4
// OGCG-NEXT: store i8 65, ptr %[[ARRAYIDX]], align 4
// OGCG-NEXT: ret void