Files
llvm-project/clang/test/CIR/CodeGen/pointer-to-data-member.cpp
Chaitanya d8ef5bcc87 [CIR] Emit target-cpu, target-features, and tune-cpu attrs on cir.func (#193458)
Add `getCPUAndFeaturesAttributes` to `CIRGenModule`, mirroring OGCG's
`GetCPUAndFeaturesAttributes`.
This sets `cir.target-cpu`, `cir.target-features` and `cir.tune-cpu`
string attributes on `cir.func`.
For AMDGPU, only features that differ from the target CPU's defaults are
emitted matching OGCG.
2026-04-29 15:37:26 +05:30

352 lines
20 KiB
C++

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> %t-before.cir
// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s
// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -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 -std=c++17 -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
struct Point {
int x;
int y;
int z;
};
int Point::*ptr_none = nullptr;
// CIR-BEFORE: cir.global external @ptr_none = #cir.data_member<null> : !cir.data_member<!s32i in !rec_Point>
// CIR-AFTER: cir.global external @ptr_none = #cir.int<-1> : !s64i
// LLVM: @ptr_none = global i64 -1
// OGCG: @ptr_none = global i64 -1
int Point::*pt_member = &Point::z;
// CIR-BEFORE: cir.global external @pt_member = #cir.data_member<2> : !cir.data_member<!s32i in !rec_Point>
// CIR-AFTER: cir.global external @pt_member = #cir.int<8> : !s64i
// LLVM: @pt_member = global i64 8
// OGCG: @pt_member = global i64 8
auto test1() -> int Point::* {
return &Point::y;
}
int Point::*pt_member_nested_region = test1();
// CIR-BEFORE: cir.global external @pt_member_nested_region = ctor : !cir.data_member<!s32i in !rec_Point> {
// CIR-BEFORE: %[[MEMBER_PTR_ADDR:.*]] = cir.get_global @pt_member_nested_region : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
// CIR-BEFORE: %[[MEMBER_PTR:.*]] = cir.call @_Z5test1v() : () -> !cir.data_member<!s32i in !rec_Point>
// CIR-BEFORE: cir.store{{.*}} %[[MEMBER_PTR]], %[[MEMBER_PTR_ADDR]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
// CIR-BEFORE: }
// CIR-AFTER: cir.global external @pt_member_nested_region = #cir.int<-1> : !s64i
// CIR-AFTER: cir.func internal private @__cxx_global_var_init()
// CIR-AFTER: %[[MEMBER_PTR_ADDR:.*]] = cir.get_global @pt_member_nested_region : !cir.ptr<!s64i>
// CIR-AFTER: %[[MEMBER_PTR:.*]] = cir.call @_Z5test1v() : () -> !s64i
// CIR-AFTER: cir.store align(8) %[[MEMBER_PTR]], %[[MEMBER_PTR_ADDR]] : !s64i, !cir.ptr<!s64i>
// LLVM: @pt_member_nested_region = global i64 -1, align 8
// LLVM: define internal void @__cxx_global_var_init()
// LLVM: %[[MEMBER_PTR:.*]] = call i64 @_Z5test1v()
// LLVM: store i64 %[[MEMBER_PTR]], ptr @pt_member_nested_region, align 8
// OGCG: @pt_member_nested_region = global i64 -1, align 8
// OGCG emits __cxx_global_var_init between test1() and test2(). See checks below.
// Checks for test1()
// CIR-BEFORE: cir.func {{.*}} @_Z5test1v() -> !cir.data_member<!s32i in !rec_Point> attributes {{{.*}}nothrow} {
// CIR-BEFORE: %[[RETVAL:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"]
// CIR-BEFORE: %[[MEMBER:.*]] = cir.const #cir.data_member<1> : !cir.data_member<!s32i in !rec_Point>
// CIR-BEFORE: cir.store %[[MEMBER]], %[[RETVAL]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
// CIR-BEFORE: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, !cir.data_member<!s32i in !rec_Point>
// CIR-BEFORE: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point>
// CIR-AFTER: cir.func {{.*}} @_Z5test1v() -> !s64i attributes {{{.*}}nothrow} {
// CIR-AFTER: %[[RETVAL:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["__retval"]
// CIR-AFTER: %[[OFFSET:.*]] = cir.const #cir.int<4> : !s64i
// CIR-AFTER: cir.store %[[OFFSET]], %[[RETVAL]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: cir.return %[[RET]] : !s64i
// LLVM: define {{.*}} i64 @_Z5test1v()
// LLVM: %[[RETVAL:.*]] = alloca i64
// LLVM: store i64 4, ptr %[[RETVAL]]
// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL]]
// LLVM: ret i64 %[[RET]]
// OGCG: define {{.*}} i64 @_Z5test1v()
// OGCG: ret i64 4
// OGCG: define internal void @__cxx_global_var_init()
// OGCG: %[[MEMBER_PTR:.*]] = call i64 @_Z5test1v()
// OGCG: store i64 %[[MEMBER_PTR]], ptr @pt_member_nested_region
int test2(const Point &pt, int Point::*member) {
return pt.*member;
}
// CIR-BEFORE: cir.func {{.*}} @_Z5test2RK5PointMS_i(
// CIR-BEFORE-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
// CIR-BEFORE: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init, const]
// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
// CIR-BEFORE: cir.store %[[PT_ARG]], %[[PT_ADDR]]
// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[PT:.*]] = cir.load %[[PT_ADDR]]
// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
// CIR-BEFORE: cir.return %[[RET]]
// CIR-AFTER: cir.func {{.*}} @_Z5test2RK5PointMS_i(
// CIR-AFTER-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
// CIR-AFTER: %[[PT_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>, ["pt", init, const]
// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR-AFTER: cir.store %[[PT_ARG]], %[[PT_ADDR]] : !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>
// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[PT:.*]] = cir.load %[[PT_ADDR]] : !cir.ptr<!cir.ptr<!rec_Point>>, !cir.ptr<!rec_Point>
// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[PT]] : !cir.ptr<!rec_Point> -> !cir.ptr<!s8i>
// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test2RK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[PT_ADDR:.*]] = alloca ptr
// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32
// LLVM: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]]
// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// LLVM: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]]
// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[PT]], i64 %[[MEMBER]]
// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]]
// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]]
// LLVM: ret i32 %[[RET]]
// OGCG: define {{.*}} i32 @_Z5test2RK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// OGCG: %[[PT_ADDR:.*]] = alloca ptr
// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64
// OGCG: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]]
// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// OGCG: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]]
// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[PT]], i64 %[[MEMBER]]
// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]]
// OGCG: ret i32 %[[RET]]
int test3(const Point *pt, int Point::*member) {
return pt->*member;
}
// CIR-BEFORE: cir.func {{.*}} @_Z5test3PK5PointMS_i(
// CIR-BEFORE-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
// CIR-BEFORE: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init]
// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
// CIR-BEFORE: cir.store %[[PT_ARG]], %[[PT_ADDR]]
// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[PT:.*]] = cir.load{{.*}} %[[PT_ADDR]]
// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
// CIR-BEFORE: cir.return %[[RET]]
// CIR-AFTER: cir.func {{.*}} @_Z5test3PK5PointMS_i(
// CIR-AFTER-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
// CIR-AFTER: %[[PT_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>, ["pt", init]
// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR-AFTER: cir.store %[[PT_ARG]], %[[PT_ADDR]] : !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>
// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[PT:.*]] = cir.load{{.*}} %[[PT_ADDR]] : !cir.ptr<!cir.ptr<!rec_Point>>, !cir.ptr<!rec_Point>
// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[PT]] : !cir.ptr<!rec_Point> -> !cir.ptr<!s8i>
// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test3PK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[PT_ADDR:.*]] = alloca ptr
// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32
// LLVM: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]]
// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// LLVM: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]]
// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[PT]], i64 %[[MEMBER]]
// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]]
// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]]
// LLVM: ret i32 %[[RET]]
// OGCG: define {{.*}} i32 @_Z5test3PK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// OGCG: %[[PT_ADDR:.*]] = alloca ptr
// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64
// OGCG: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]]
// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// OGCG: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]]
// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[PT]], i64 %[[MEMBER]]
// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]]
// OGCG: ret i32 %[[RET]]
struct Incomplete;
auto test4(int Incomplete::*member) -> int Incomplete::* {
return member;
}
// CIR-BEFORE: cir.func {{.*}} @_Z5test4M10Incompletei(
// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
// CIR-BEFORE: cir.store %[[MEMBER]], %[[RETVAL_ADDR]]
// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
// CIR-BEFORE: cir.return %[[RET]]
// CIR-AFTER: cir.func {{.*}} @_Z5test4M10Incompletei(
// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["__retval"]
// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: cir.store %[[MEMBER]], %[[RETVAL_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: cir.return %[[RET]] : !s64i
// LLVM: define {{.*}} i64 @_Z5test4M10Incompletei(i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i64
// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// LLVM: store i64 %[[MEMBER]], ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL_ADDR]]
// LLVM: ret i64 %[[RET]]
// OGCG: define {{.*}} i64 @_Z5test4M10Incompletei(i64 %[[MEMBER_ARG:.*]])
// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64
// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// OGCG: ret i64 %[[MEMBER]]
int test5(Incomplete *ic, int Incomplete::*member) {
return ic->*member;
}
// CIR-BEFORE: cir.func {{.*}} @_Z5test5P10IncompleteMS_i(
// CIR-BEFORE-SAME: %[[IC_ARG:.*]]: !cir.ptr<!rec_Incomplete>
// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
// CIR-BEFORE: %[[IC_ADDR:.*]] = cir.alloca {{.*}} ["ic", init]
// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
// CIR-BEFORE: cir.store %[[IC_ARG]], %[[IC_ADDR]]
// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[IC:.*]] = cir.load{{.*}} %[[IC_ADDR]]
// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[IC]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Incomplete>] : !cir.ptr<!rec_Incomplete> -> !cir.ptr<!s32i>
// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
// CIR-BEFORE: cir.return %[[RET]]
// CIR-AFTER: cir.func {{.*}} @_Z5test5P10IncompleteMS_i(
// CIR-AFTER-SAME: %[[IC_ARG:.*]]: !cir.ptr<!rec_Incomplete>
// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
// CIR-AFTER: %[[IC_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Incomplete>, !cir.ptr<!cir.ptr<!rec_Incomplete>>, ["ic", init]
// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR-AFTER: cir.store %[[IC_ARG]], %[[IC_ADDR]] : !cir.ptr<!rec_Incomplete>, !cir.ptr<!cir.ptr<!rec_Incomplete>>
// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR-AFTER: %[[IC:.*]] = cir.load{{.*}} %[[IC_ADDR]] : !cir.ptr<!cir.ptr<!rec_Incomplete>>, !cir.ptr<!rec_Incomplete>
// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[IC]] : !cir.ptr<!rec_Incomplete> -> !cir.ptr<!s8i>
// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test5P10IncompleteMS_i(ptr {{.*}} %[[IC_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[IC_ADDR:.*]] = alloca ptr
// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32
// LLVM: store ptr %[[IC_ARG]], ptr %[[IC_ADDR]]
// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// LLVM: %[[IC:.*]] = load ptr, ptr %[[IC_ADDR]]
// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[IC]], i64 %[[MEMBER]]
// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]]
// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]]
// LLVM: ret i32 %[[RET]]
// OGCG: define {{.*}} i32 @_Z5test5P10IncompleteMS_i(ptr {{.*}} %[[IC_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// OGCG: %[[IC_ADDR:.*]] = alloca ptr
// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64
// OGCG: store ptr %[[IC_ARG]], ptr %[[IC_ADDR]]
// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]]
// OGCG: %[[IC:.*]] = load ptr, ptr %[[IC_ADDR]]
// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]]
// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[IC]], i64 %[[MEMBER]]
// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]]
// OGCG: ret i32 %[[RET]]
auto test_null() -> int Point::* {
return nullptr;
}
// CIR: cir.func {{.*}} @_Z9test_nullv() -> !cir.data_member<!s32i in !rec_Point> {
// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"]
// CIR: %[[CONST_NULL:.*]] = cir.const #cir.data_member<null> : !cir.data_member<!s32i in !rec_Point>
// CIR: cir.store %[[CONST_NULL]], %[[RETVAL_ADDR]]
// CIR: %[[RET:.*]] = cir.load %[[RETVAL_ADDR]]
// CIR: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point>
// LLVM: define {{.*}} i64 @_Z9test_nullv()
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i64
// LLVM: store i64 -1, ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL_ADDR]]
// LLVM: ret i64 %[[RET]]
// OGCG: define {{.*}} i64 @_Z9test_nullv()
// OGCG: ret i64 -1
auto test_null_incomplete() -> int Incomplete::* {
return nullptr;
}
// CIR: cir.func {{.*}} @_Z20test_null_incompletev() -> !cir.data_member<!s32i in !rec_Incomplete> {
// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Incomplete>, !cir.ptr<!cir.data_member<!s32i in !rec_Incomplete>>, ["__retval"]
// CIR: %[[CONST_NULL:.*]] = cir.const #cir.data_member<null> : !cir.data_member<!s32i in !rec_Incomplete>
// CIR: cir.store %[[CONST_NULL]], %[[RETVAL_ADDR]]
// CIR: %[[RET:.*]] = cir.load %[[RETVAL_ADDR]]
// CIR: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Incomplete>
// LLVM: define {{.*}} i64 @_Z20test_null_incompletev()
// LLVM: %[[RETVAL_ADDR:.*]] = alloca i64
// LLVM: store i64 -1, ptr %[[RETVAL_ADDR]]
// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL_ADDR]]
// LLVM: ret i64 %[[RET]]
// OGCG: define {{.*}} i64 @_Z20test_null_incompletev()
// OGCG: ret i64 -1