// 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 // CIR: !rec_IncompleteC = !cir.record // CIR: !rec_Base = !cir.record // CIR: !rec_CompleteC = !cir.record // CIR: !rec_Derived = !cir.record // Note: LLVM and OGCG do not emit the type for incomplete classes. // LLVM: %class.CompleteC = type { i32, i8 } // LLVM: %class.Derived = type { %class.Base, i32 } // LLVM: %class.Base = type { i32 } // OGCG: %class.CompleteC = type { i32, i8 } // OGCG: %class.Derived = type { %class.Base, i32 } // OGCG: %class.Base = type { i32 } class IncompleteC; IncompleteC *p; // CIR: cir.global external @p = #cir.ptr : !cir.ptr // LLVM: @p = global ptr null // OGCG: @p = global ptr null, align 8 class CompleteC { public: int a; char b; }; CompleteC cc; // CIR: cir.global external @cc = #cir.zero : !rec_CompleteC // LLVM: @cc = global %class.CompleteC zeroinitializer // OGCG: @cc = global %class.CompleteC zeroinitializer class Base { public: int a; }; class Derived : public Base { public: int b; }; int use(Derived *d) { return d->b; } // CIR: cir.func{{.*}} @_Z3useP7Derived(%[[ARG0:.*]]: !cir.ptr // CIR: %[[D_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] // CIR: cir.store %[[ARG0]], %[[D_ADDR]] // CIR: %[[D_PTR:.*]] = cir.load align(8) %0 // CIR: %[[D_B_ADDR:.*]] = cir.get_member %[[D_PTR]][1] {name = "b"} // CIR: %[[D_B:.*]] = cir.load align(4) %[[D_B_ADDR]] // LLVM: define{{.*}} i32 @_Z3useP7Derived // LLVM: getelementptr %class.Derived, ptr %{{.*}}, i32 0, i32 1 // OGCG: define{{.*}} i32 @_Z3useP7Derived // OGCG: getelementptr inbounds nuw %class.Derived, ptr %{{.*}}, i32 0, i32 1 int use_base() { Derived d; return d.a; } // CIR: cir.func{{.*}} @_Z8use_basev // CIR: %[[D_ADDR:.*]] = cir.alloca !rec_Derived, !cir.ptr, ["d"] // CIR: %[[BASE_ADDR:.*]] cir.base_class_addr %[[D_ADDR]] : !cir.ptr nonnull [0] -> !cir.ptr // CIR: %[[D_A_ADDR:.*]] = cir.get_member %2[0] {name = "a"} : !cir.ptr -> !cir.ptr // CIR: %[[D_A:.*]] = cir.load align(4) %3 : !cir.ptr, !s32i // LLVM: define{{.*}} i32 @_Z8use_basev // LLVM: %[[D:.*]] = alloca %class.Derived // LLVM: %[[D_A_ADDR:.*]] = getelementptr %class.Base, ptr %[[D]], i32 0, i32 0 // OGCG: define{{.*}} i32 @_Z8use_basev // OGCG: %[[D:.*]] = alloca %class.Derived // OGCG: %[[D_A_ADDR:.*]] = getelementptr inbounds nuw %class.Base, ptr %[[D]], i32 0, i32 0 int use_base_via_pointer(Derived *d) { return d->a; } // CIR: cir.func{{.*}} @_Z20use_base_via_pointerP7Derived(%[[ARG0:.*]]: !cir.ptr // CIR: %[[D_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] // CIR: cir.store %[[ARG0]], %[[D_ADDR]] // CIR: %[[D:.*]] = cir.load align(8) %[[D_ADDR]] // CIR: %[[BASE_ADDR:.*]] = cir.base_class_addr %[[D]] : !cir.ptr nonnull [0] -> !cir.ptr // CIR: %[[D_A_ADDR:.*]] = cir.get_member %[[BASE_ADDR]][0] {name = "a"} // CIR: %[[D_A:.*]] = cir.load align(4) %[[D_A_ADDR]] // LLVM: define{{.*}} i32 @_Z20use_base_via_pointerP7Derived // LLVM: %[[D_A_ADDR:.*]] = getelementptr %class.Base, ptr %{{.*}}, i32 0, i32 0 // OGCG: define{{.*}} i32 @_Z20use_base_via_pointerP7Derived // OGCG: %[[D_A_ADDR:.*]] = getelementptr inbounds nuw %class.Base, ptr %{{.*}}, i32 0, i32 0