Files
clang-p2996/clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp
Nikita Popov e56a6a2683 Reapply [CaptureTracking][FunctionAttrs] Add support for CaptureInfo (#125880) (#128020)
Relative to the previous attempt this includes two fixes:
 * Adjust callCapturesBefore() to not skip captures(ret: address,
    provenance) arguments, as these will not count as a capture
    at the call-site.
 * When visiting uses during stack slot optimization, don't skip
    the ModRef check for passthru captures. Calls can both modref
    and be passthru for captures.

------

This extends CaptureTracking to support inferring non-trivial
CaptureInfos. The focus of this patch is to only support FunctionAttrs,
other users of CaptureTracking will be updated in followups.

The key API changes here are:

* DetermineUseCaptureKind() now returns a UseCaptureInfo where the UseCC
component specifies what is captured at that Use and the ResultCC
component specifies what may be captured via the return value of the
User. Usually only one or the other will be used (corresponding to
previous MAY_CAPTURE or PASSTHROUGH results), but both may be set for
call captures.
* The CaptureTracking::captures() extension point is passed this
UseCaptureInfo as well and then can decide what to do with it by
returning an Action, which is one of: Stop: stop traversal.
ContinueIgnoringReturn: continue traversal but don't follow the
instruction return value. Continue: continue traversal and follow the
instruction return value if it has additional CaptureComponents.

For now, this patch retains the (unsound) special logic for comparison
of null with a dereferenceable pointer. I'd like to switch key code to
take advantage of address/address_is_null before dropping it.

This PR mainly intends to introduce necessary API changes and basic
inference support, there are various possible improvements marked with
TODOs.
2025-02-27 09:38:29 +01:00

74 lines
2.7 KiB
C++

// dynamic_cast
// Ensure that dynamic casting works normally
// RUN: %clang_cc1 %s -triple=aarch64-unknown-fuchsia -O3 -o - -emit-llvm | FileCheck %s
// CHECK: define{{.*}} ptr @_Z6upcastP1B(ptr noundef readnone returned captures(ret: address, provenance) %b) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: ret ptr %b
// CHECK-NEXT: }
// CHECK: define{{.*}} ptr @_Z8downcastP1A(ptr noundef readonly %a) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: [[isnull:%[0-9]+]] = icmp eq ptr %a, null
// CHECK-NEXT: br i1 [[isnull]], label %[[dynamic_cast_end:[a-z0-9._]+]], label %[[dynamic_cast_notnull:[a-z0-9._]+]]
// CHECK: [[dynamic_cast_notnull]]:
// CHECK-NEXT: [[as_b:%[0-9]+]] = tail call ptr @__dynamic_cast(ptr nonnull %a, ptr nonnull @_ZTI1A, ptr nonnull @_ZTI1B, i64 0)
// CHECK-NEXT: br label %[[dynamic_cast_end]]
// CHECK: [[dynamic_cast_end]]:
// CHECK-NEXT: [[res:%[0-9]+]] = phi ptr [ [[as_b]], %[[dynamic_cast_notnull]] ], [ null, %entry ]
// CHECK-NEXT: ret ptr [[res]]
// CHECK-NEXT: }
// CHECK: declare ptr @__dynamic_cast(ptr, ptr, ptr, i64) local_unnamed_addr
// CHECK: define{{.*}} ptr @_Z8selfcastP1B(ptr noundef readnone returned captures(ret: address, provenance) %b) local_unnamed_addr
// CHECK-NEXT: entry
// CHECK-NEXT: ret ptr %b
// CHECK-NEXT: }
// CHECK: define{{.*}} ptr @_Z9void_castP1B(ptr noundef readonly captures(address_is_null, ret: address, provenance) %b) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: [[isnull:%[0-9]+]] = icmp eq ptr %b, null
// CHECK-NEXT: br i1 [[isnull]], label %[[dynamic_cast_end:[a-z0-9._]+]], label %[[dynamic_cast_notnull:[a-z0-9._]+]]
// CHECK: [[dynamic_cast_notnull]]:
// CHECK-DAG: [[vtable:%[a-z0-9]+]] = load ptr, ptr %b, align 8
// CHECK-DAG: [[offset_ptr:%.+]] = getelementptr inbounds i8, ptr [[vtable]], i64 -8
// CHECK-DAG: [[offset_to_top:%.+]] = load i32, ptr [[offset_ptr]], align 4
// CHECK-DAG: [[offset_to_top2:%.+]] = sext i32 [[offset_to_top]] to i64
// CHECK-DAG: [[casted:%.+]] = getelementptr inbounds i8, ptr %b, i64 [[offset_to_top2]]
// CHECK-NEXT: br label %[[dynamic_cast_end]]
// CHECK: [[dynamic_cast_end]]:
// CHECK-NEXT: [[res:%[0-9]+]] = phi ptr [ [[casted]], %[[dynamic_cast_notnull]] ], [ null, %entry ]
// CHECK-NEXT: ret ptr [[res]]
// CHECK-NEXT: }
class A {
public:
virtual void foo();
};
class B : public A {
public:
void foo() override;
};
void A::foo() {}
void B::foo() {}
A *upcast(B *b) {
return dynamic_cast<A *>(b);
}
B *downcast(A *a) {
return dynamic_cast<B *>(a);
}
B *selfcast(B *b) {
return dynamic_cast<B *>(b);
}
void *void_cast(B *b) {
return dynamic_cast<void *>(b);
}