// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR %s < %t.cir // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --check-prefix=LLVM %s < %t-cir.ll // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=OGCG %s < %t.ll int test_load(volatile int *ptr) { return *ptr; } // CIR: cir.func dso_local @_Z9test_loadPVi // CIR: cir.load volatile // LLVM: define {{.*}} i32 @_Z9test_loadPVi // LLVM: load volatile i32, ptr %{{.*}} // OGCG: define {{.*}} i32 @_Z9test_loadPVi // OGCG: load volatile i32, ptr %{{.*}} void test_store(volatile int *ptr) { *ptr = 42; } // CIR: cir.func dso_local @_Z10test_storePVi // CIR: cir.store volatile // LLVM: define {{.*}} void @_Z10test_storePVi // LLVM: store volatile i32 42, ptr %{{.*}} // OGCG: define {{.*}} void @_Z10test_storePVi // OGCG: store volatile i32 42, ptr %{{.*}} struct Foo { int x; volatile int y; volatile int z: 4; }; int test_load_field1(volatile Foo *ptr) { return ptr->x; } // CIR: cir.func dso_local @_Z16test_load_field1PV3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]] // LLVM: define {{.*}} i32 @_Z16test_load_field1PV3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 0 // LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} i32 @_Z16test_load_field1PV3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 0 // OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]] int test_load_field2(Foo *ptr) { return ptr->y; } // CIR: cir.func dso_local @_Z16test_load_field2P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]] // LLVM: define {{.*}} i32 @_Z16test_load_field2P3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 1 // LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} i32 @_Z16test_load_field2P3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 1 // OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]] int test_load_field3(Foo *ptr) { return ptr->z; } // CIR: cir.func dso_local @_Z16test_load_field3P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.*}} = cir.get_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] {is_volatile} : !cir.ptr) -> !s32i // LLVM: define {{.*}} i32 @_Z16test_load_field3P3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 2 // LLVM: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]] // LLVM: %[[TMP2:.*]] = shl i8 %[[TMP1]], 4 // LLVM: %[[TMP3:.*]] = ashr i8 %[[TMP2]], 4 // LLVM: %{{.*}} = sext i8 %[[TMP3]] to i32 // OGCG: define {{.*}} i32 @_Z16test_load_field3P3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 2 // OGCG: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]] // OGCG: %[[TMP2:.*]] = shl i8 %[[TMP1]], 4 // OGCG: %[[TMP3:.*]] = ashr i8 %[[TMP2]], 4 // OGCG: %{{.*}} = sext i8 %[[TMP3]] to i32 void test_store_field1(volatile Foo *ptr) { ptr->x = 42; } // CIR: cir.func dso_local @_Z17test_store_field1PV3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]] // LLVM: define {{.*}} void @_Z17test_store_field1PV3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 0 // LLVM: store volatile i32 42, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} void @_Z17test_store_field1PV3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 0 // OGCG: store volatile i32 42, ptr %[[MEMBER_ADDR]] void test_store_field2(Foo *ptr) { ptr->y = 42; } // CIR: cir.func dso_local @_Z17test_store_field2P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]] // LLVM: define {{.*}} void @_Z17test_store_field2P3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 1 // LLVM: store volatile i32 42, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} void @_Z17test_store_field2P3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 1 // OGCG: store volatile i32 42, ptr %[[MEMBER_ADDR]] void test_store_field3(Foo *ptr) { ptr->z = 4; } // CIR: cir.func dso_local @_Z17test_store_field3P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.set_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] : !cir.ptr, %1 : !s32i) {is_volatile} // LLVM: define {{.*}} void @_Z17test_store_field3P3Foo // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 2 // LLVM: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]] // LLVM: %[[TMP2:.*]] = and i8 %[[TMP1]], -16 // LLVM: %[[TMP3:.*]] = or i8 %[[TMP2]], 4 // LLVM: store volatile i8 %[[TMP3]], ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} void @_Z17test_store_field3P3Foo // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 2 // OGCG: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]] // OGCG: %[[TMP2:.*]] = and i8 %[[TMP1]], -16 // OGCG: %[[TMP3:.*]] = or i8 %[[TMP2]], 4 // OGCG: store volatile i8 %[[TMP3]], ptr %[[MEMBER_ADDR]] struct A { int x; void set_x(int val) volatile; int get_x() volatile; }; void A::set_x(int val) volatile { x = val; } // CIR: cir.func dso_local @_ZNV1A5set_xEi // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"} // CIR: cir.store volatile {{.*}} %{{.*}}, %[[MEMBER_ADDR]] // LLVM: define {{.*}} void @_ZNV1A5set_xEi // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.A, ptr %{{.*}}, i32 0, i32 0 // LLVM: store volatile i32 %{{.*}}, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} void @_ZNV1A5set_xEi // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.A, ptr %{{.*}}, i32 0, i32 0 // OGCG: store volatile i32 %{{.*}}, ptr %[[MEMBER_ADDR]] int A::get_x() volatile { return x; } // CIR: cir.func dso_local @_ZNV1A5get_xEv // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"} // CIR: cir.load volatile {{.*}} %[[MEMBER_ADDR]] // LLVM: define {{.*}} i32 @_ZNV1A5get_xEv // LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.A, ptr %{{.*}}, i32 0, i32 0 // LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]] // OGCG: define {{.*}} i32 @_ZNV1A5get_xEv // OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.A, ptr %{{.*}}, i32 0, i32 0 // OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]