209 lines · cpp
1// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -fclangir -clangir-disable-passes -emit-cir -o %t.cir %s2// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR3// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -fclangir -emit-llvm -o %t-cir.ll %s4// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s5// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -emit-llvm -o %t.ll %s6// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s7 8struct Base1 {9 virtual ~Base1();10};11 12struct Base2 {13 virtual ~Base2();14};15 16struct Derived final : Base1 {};17 18Derived *ptr_cast(Base1 *ptr) {19 return dynamic_cast<Derived *>(ptr);20}21 22// CIR: cir.func {{.*}} @_Z8ptr_castP5Base123// CIR: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base1>>, !cir.ptr<!rec_Base1>24// CIR-NEXT: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null>25// CIR-NEXT: %[[SRC_IS_NULL:.*]] = cir.cmp(eq, %[[SRC]], %[[NULL_PTR]])26// CIR-NEXT: %[[RESULT:.*]] = cir.ternary(%[[SRC_IS_NULL]], true {27// CIR-NEXT: %[[NULL_PTR_DEST:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Derived>28// CIR-NEXT: cir.yield %[[NULL_PTR_DEST]] : !cir.ptr<!rec_Derived>29// CIR-NEXT: }, false {30// CIR-NEXT: %[[EXPECTED_VPTR:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 2>) : !cir.vptr31// CIR-NEXT: %[[SRC_VPTR_PTR:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_Base1> -> !cir.ptr<!cir.vptr>32// CIR-NEXT: %[[SRC_VPTR:.*]] = cir.load{{.*}} %[[SRC_VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr33// CIR-NEXT: %[[SUCCESS:.*]] = cir.cmp(eq, %[[SRC_VPTR]], %[[EXPECTED_VPTR]]) : !cir.vptr, !cir.bool34// CIR-NEXT: %[[EXACT_RESULT:.*]] = cir.ternary(%[[SUCCESS]], true {35// CIR-NEXT: %[[RES:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_Base1> -> !cir.ptr<!rec_Derived>36// CIR-NEXT: cir.yield %[[RES]] : !cir.ptr<!rec_Derived>37// CIR-NEXT: }, false {38// CIR-NEXT: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Derived>39// CIR-NEXT: cir.yield %[[NULL]] : !cir.ptr<!rec_Derived>40// CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>41// CIR-NEXT: cir.yield %[[EXACT_RESULT]] : !cir.ptr<!rec_Derived>42// CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>43 44// Note: The LLVM output omits the label for the entry block (which is45// implicitly %1), so we use %{{.*}} to match the implicit label in the46// phi check.47 48// LLVM: define dso_local ptr @_Z8ptr_castP5Base1(ptr{{.*}} %[[SRC:.*]])49// LLVM-NEXT: %[[SRC_IS_NULL:.*]] = icmp eq ptr %0, null50// LLVM-NEXT: br i1 %[[SRC_IS_NULL]], label %[[LABEL_END:.*]], label %[[LABEL_NOTNULL:.*]]51// LLVM: [[LABEL_NOTNULL]]:52// LLVM-NEXT: %[[VPTR:.*]] = load ptr, ptr %[[SRC]], align 853// LLVM-NEXT: %[[SUCCESS:.*]] = icmp eq ptr %[[VPTR]], getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 16)54// LLVM-NEXT: %[[EXACT_RESULT:.*]] = select i1 %[[SUCCESS]], ptr %[[SRC]], ptr null55// LLVM-NEXT: br label %[[LABEL_END]]56// LLVM: [[LABEL_END]]:57// LLVM-NEXT: %[[RESULT:.*]] = phi ptr [ %[[EXACT_RESULT]], %[[LABEL_NOTNULL]] ], [ null, %{{.*}} ]58// LLVM-NEXT: ret ptr %[[RESULT]]59// LLVM-NEXT: }60 61// OGCG: define{{.*}} ptr @_Z8ptr_castP5Base1(ptr {{.*}} %[[SRC:.*]])62// OGCG-NEXT: entry:63// OGCG-NEXT: %[[NULL_CHECK:.*]] = icmp eq ptr %[[SRC]], null64// OGCG-NEXT: br i1 %[[NULL_CHECK]], label %[[LABEL_NULL:.*]], label %[[LABEL_NOTNULL:.*]]65// OGCG: [[LABEL_NOTNULL]]:66// OGCG-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[SRC]], align 867// OGCG-NEXT: %[[VTABLE_CHECK:.*]] = icmp eq ptr %[[VTABLE]], getelementptr inbounds {{.*}} (i8, ptr @_ZTV7Derived, i64 16)68// OGCG-NEXT: br i1 %[[VTABLE_CHECK]], label %[[LABEL_END:.*]], label %[[LABEL_NULL]]69// OGCG: [[LABEL_NULL]]:70// OGCG-NEXT: br label %[[LABEL_END]]71// OGCG: [[LABEL_END]]:72// OGCG-NEXT: %[[RESULT:.*]] = phi ptr [ %[[SRC]], %[[LABEL_NOTNULL]] ], [ null, %[[LABEL_NULL]] ]73// OGCG-NEXT: ret ptr %[[RESULT]]74// OGCG-NEXT: }75 76Derived &ref_cast(Base1 &ref) {77 return dynamic_cast<Derived &>(ref);78}79 80// CIR: cir.func {{.*}} @_Z8ref_castR5Base181// CIR: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base1>>, !cir.ptr<!rec_Base1>82// CIR-NEXT: %[[EXPECTED_VPTR:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 2>) : !cir.vptr83// CIR-NEXT: %[[SRC_VPTR_PTR:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_Base1> -> !cir.ptr<!cir.vptr>84// CIR-NEXT: %[[SRC_VPTR:.*]] = cir.load{{.*}} %[[SRC_VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr85// CIR-NEXT: %[[SUCCESS:.*]] = cir.cmp(eq, %[[SRC_VPTR]], %[[EXPECTED_VPTR]]) : !cir.vptr, !cir.bool86// CIR-NEXT: %[[FAILED:.*]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool87// CIR-NEXT: cir.if %[[FAILED]] {88// CIR-NEXT: cir.call @__cxa_bad_cast() : () -> ()89// CIR-NEXT: cir.unreachable90// CIR-NEXT: }91// CIR-NEXT: %{{.+}} = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_Base1> -> !cir.ptr<!rec_Derived>92 93// LLVM: define{{.*}} ptr @_Z8ref_castR5Base1(ptr{{.*}} %[[SRC:.*]])94// LLVM-NEXT: %[[VPTR:.*]] = load ptr, ptr %[[SRC]], align 895// LLVM-NEXT: %[[OK:.*]] = icmp eq ptr %[[VPTR]], getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 16)96// LLVM-NEXT: br i1 %[[OK]], label %[[LABEL_OK:.*]], label %[[LABEL_FAIL:.*]]97// LLVM: [[LABEL_FAIL]]:98// LLVM-NEXT: tail call void @__cxa_bad_cast()99// LLVM-NEXT: unreachable100// LLVM: [[LABEL_OK]]:101// LLVM-NEXT: ret ptr %[[SRC]]102// LLVM-NEXT: }103 104// OGCG: define{{.*}} ptr @_Z8ref_castR5Base1(ptr {{.*}} %[[REF:.*]])105// OGCG-NEXT: entry:106// OGCG-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[REF]], align 8107// OGCG-NEXT: %[[VTABLE_CHECK:.*]] = icmp eq ptr %[[VTABLE]], getelementptr inbounds {{.*}} (i8, ptr @_ZTV7Derived, i64 16)108// OGCG-NEXT: br i1 %[[VTABLE_CHECK]], label %[[LABEL_END:.*]], label %[[LABEL_NULL:.*]]109// OGCG: [[LABEL_NULL]]:110// OGCG-NEXT: {{.*}}call void @__cxa_bad_cast()111// OGCG-NEXT: unreachable112// OGCG: [[LABEL_END]]:113// OGCG-NEXT: ret ptr %[[REF]]114// OGCG-NEXT: }115 116struct Offset { virtual ~Offset(); };117struct A { virtual ~A(); };118struct B final : Offset, A { };119 120B *offset_cast(A *a) {121 return dynamic_cast<B*>(a);122}123 124// CIR: cir.func {{.*}} @_Z11offset_castP1A125// CIR: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A>126// CIR-NEXT: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null>127// CIR-NEXT: %[[SRC_IS_NULL:.*]] = cir.cmp(eq, %[[SRC]], %[[NULL_PTR]])128// CIR-NEXT: %[[RESULT:.*]] = cir.ternary(%[[SRC_IS_NULL]], true {129// CIR-NEXT: %[[NULL_PTR_DEST:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_B>130// CIR-NEXT: cir.yield %[[NULL_PTR_DEST]] : !cir.ptr<!rec_B>131// CIR-NEXT: }, false {132// CIR-NEXT: %[[EXPECTED_VPTR:.*]] = cir.vtable.address_point(@_ZTV1B, address_point = <index = 1, offset = 2>) : !cir.vptr133// CIR-NEXT: %[[SRC_VPTR_PTR:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr>134// CIR-NEXT: %[[SRC_VPTR:.*]] = cir.load{{.*}} %[[SRC_VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr135// CIR-NEXT: %[[SUCCESS:.*]] = cir.cmp(eq, %[[SRC_VPTR]], %[[EXPECTED_VPTR]]) : !cir.vptr, !cir.bool136// CIR-NEXT: %[[EXACT_RESULT:.*]] = cir.ternary(%[[SUCCESS]], true {137// CIR-NEXT: %[[MINUS_EIGHT:.*]] = cir.const #cir.int<18446744073709551608> : !u64i138// CIR-NEXT: %[[SRC_VOID:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_A> -> !cir.ptr<!u8i>139// CIR-NEXT: %[[SRC_OFFSET:.*]] = cir.ptr_stride %[[SRC_VOID]], %[[MINUS_EIGHT]]140// CIR-NEXT: %[[RES:.*]] = cir.cast bitcast %[[SRC_OFFSET]] : !cir.ptr<!u8i> -> !cir.ptr<!rec_B>141// CIR-NEXT: cir.yield %[[RES]] : !cir.ptr<!rec_B>142// CIR-NEXT: }, false {143// CIR-NEXT: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_B>144// CIR-NEXT: cir.yield %[[NULL]] : !cir.ptr<!rec_B>145// CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_B>146// CIR-NEXT: cir.yield %[[EXACT_RESULT]] : !cir.ptr<!rec_B>147// CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_B>148 149// LLVM: define dso_local ptr @_Z11offset_castP1A(ptr{{.*}} %[[SRC:.*]])150// LLVM-NEXT: %[[SRC_IS_NULL:.*]] = icmp eq ptr %0, null151// LLVM-NEXT: br i1 %[[SRC_IS_NULL]], label %[[LABEL_END:.*]], label %[[LABEL_NOTNULL:.*]]152// LLVM: [[LABEL_NOTNULL]]:153// LLVM-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[SRC]]154// LLVM-NEXT: %[[VTABLE_CHECK:.*]] = icmp eq ptr %[[VTABLE]], getelementptr inbounds nuw (i8, ptr @_ZTV1B, i64 48)155// LLVM-NEXT: %[[SRC_OFFSET:.*]] = getelementptr i8, ptr %[[SRC]], i64 -8156// LLVM-NEXT: %[[EXACT_RESULT:.*]] = select i1 %[[VTABLE_CHECK]], ptr %[[SRC_OFFSET]], ptr null157// LLVM-NEXT: br label %[[LABEL_END]]158// LLVM: [[LABEL_END]]:159// LLVM-NEXT: %[[RESULT:.*]] = phi ptr [ %[[EXACT_RESULT]], %[[LABEL_NOTNULL]] ], [ null, %{{.*}} ]160// LLVM-NEXT: ret ptr %[[RESULT]]161// LLVM-NEXT: }162 163// OGCG: define{{.*}} ptr @_Z11offset_castP1A(ptr{{.*}} %[[SRC:.*]])164// OGCG: %[[SRV_NULL:.*]] = icmp eq ptr %[[SRC]], null165// OGCG-NEXT: br i1 %[[SRV_NULL]], label %[[LABEL_NULL:.*]], label %[[LABEL_NOTNULL:.*]]166// OGCG: [[LABEL_NOTNULL]]:167// OGCG-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[SRC]]168// OGCG-NEXT: %[[VTABLE_CHECK:.*]] = icmp eq ptr %[[VTABLE]], getelementptr inbounds nuw inrange(-16, 16) (i8, ptr @_ZTV1B, i64 48)169// OGCG-NEXT: %[[RESULT:.*]] = getelementptr inbounds i8, ptr %[[SRC]], i64 -8170// OGCG-NEXT: br i1 %[[VTABLE_CHECK]], label %[[LABEL_END:.*]], label %[[LABEL_NULL]]171// OGCG: [[LABEL_NULL]]:172// OGCG-NEXT: br label %[[LABEL_END]]173// OGCG: [[LABEL_END]]:174// OGCG-NEXT: phi ptr [ %[[RESULT]], %[[LABEL_NOTNULL]] ], [ null, %[[LABEL_NULL]] ]175 176Derived *ptr_cast_always_fail(Base2 *ptr) {177 return dynamic_cast<Derived *>(ptr);178 }179 180// CIR: cir.func {{.*}} @_Z20ptr_cast_always_failP5Base2181// CIR: %{{.+}} = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base2>>, !cir.ptr<!rec_Base2>182// CIR-NEXT: %[[RESULT:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Derived>183// CIR-NEXT: cir.store %[[RESULT]], %{{.*}} : !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>184 185// LLVM: define {{.*}} ptr @_Z20ptr_cast_always_failP5Base2186// LLVM-NEXT: ret ptr null187 188// OGCG: define {{.*}} ptr @_Z20ptr_cast_always_failP5Base2189// OGCG-NEXT: entry:190// OGCG-NEXT: ret ptr null191 192Derived &ref_cast_always_fail(Base2 &ref) {193 return dynamic_cast<Derived &>(ref);194}195 196// CIR: cir.func {{.*}} @_Z20ref_cast_always_failR5Base2197// CIR: %{{.+}} = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base2>>, !cir.ptr<!rec_Base2>198// CIR-NEXT: cir.call @__cxa_bad_cast() : () -> ()199// CIR-NEXT: cir.unreachable200 201// LLVM: define {{.*}} ptr @_Z20ref_cast_always_failR5Base2202// LLVM-NEXT: tail call void @__cxa_bad_cast()203// LLVM-NEXT: unreachable204 205// OGCG: define {{.*}} ptr @_Z20ref_cast_always_failR5Base2206// OGCG-NEXT: entry:207// OGCG-NEXT: tail call void @__cxa_bad_cast()208// OGCG-NEXT: unreachable209