@@ -39,7 +39,7 @@ Derived *ptr_cast(Base1 *ptr) {
3939// CIR-NEXT: cir.yield %[[NULL]] : !cir.ptr<!rec_Derived>
4040// CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>
4141// CIR-NEXT: cir.yield %[[EXACT_RESULT]] : !cir.ptr<!rec_Derived>
42- // CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>
42+ // CIR-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>
4343
4444// Note: The LLVM output omits the label for the entry block (which is
4545// implicitly %1), so we use %{{.*}} to match the implicit label in the
@@ -112,3 +112,63 @@ Derived &ref_cast(Base1 &ref) {
112112// OGCG: [[LABEL_END]]:
113113// OGCG-NEXT: ret ptr %[[REF]]
114114// OGCG-NEXT: }
115+
116+ struct Offset { virtual ~Offset (); };
117+ struct A { virtual ~A (); };
118+ struct B final : Offset, A { };
119+
120+ B *offset_cast (A *a) {
121+ return dynamic_cast <B*>(a);
122+ }
123+
124+ // CIR: cir.func {{.*}} @_Z11offset_castP1A
125+ // 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.vptr
133+ // 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.vptr
135+ // CIR-NEXT: %[[SUCCESS:.*]] = cir.cmp(eq, %[[SRC_VPTR]], %[[EXPECTED_VPTR]]) : !cir.vptr, !cir.bool
136+ // CIR-NEXT: %[[EXACT_RESULT:.*]] = cir.ternary(%[[SUCCESS]], true {
137+ // CIR-NEXT: %[[MINUS_EIGHT:.*]] = cir.const #cir.int<18446744073709551608> : !u64i
138+ // 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, null
151+ // 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 -8
156+ // LLVM-NEXT: %[[EXACT_RESULT:.*]] = select i1 %[[VTABLE_CHECK]], ptr %[[SRC_OFFSET]], ptr null
157+ // 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]], null
165+ // 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 -8
170+ // 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]] ]
0 commit comments