Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,6 @@ declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
; CHECK-SAME: i32 0
; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2

@vtable2 = internal unnamed_addr constant { [4 x i32] } { [4 x i32] [
i32 42,
i32 1337,
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32),
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc4_dead_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32)
]}, align 4, !type !3, !type !4, !vcall_visibility !{i64 2}
!3 = !{i64 8, !"vfunc3.type"}
!4 = !{i64 12, !"vfunc4.type"}

; CHECK: @vtable2 = internal unnamed_addr constant { [4 x i32] } { [4 x i32] [
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32),
; CHECK-SAME: i32 0
; CHECK-SAME: ] }, align 4, !type !3, !type !4, !vcall_visibility !2

; (1) vfunc1_live is referenced from @main, stays alive
define internal void @vfunc1_live() {
; CHECK: define internal void @vfunc1_live(
Expand All @@ -45,19 +31,9 @@ define internal void @vfunc2_dead() {
ret void
}

; (3) vfunc3_live_extern is referenced from @main, stays alive
; CHECK: declare void @vfunc3_live_extern
declare void @vfunc3_live_extern()

; (4) vfunc4_dead_extern is never referenced, gets removed and vtable slot is null'd
; CHECK-NOT: declare void @vfunc4_dead_extern
declare void @vfunc4_dead_extern()

define void @main() {
%1 = ptrtoint ptr @vtable to i64 ; to keep @vtable alive
%2 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc1.type")
%3 = ptrtoint ptr @vtable2 to i64 ; to keep @vtable2 alive
%4 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc3.type")
ret void
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,6 @@ declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
; CHECK-SAME: i32 0
; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2

; Similar to above, but the vtable is more aligned to how C++ relative vtables look.
; That is, the functions may not be dso-local.
@vtable2 = internal unnamed_addr constant { [2 x i32] } { [2 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc4_dead_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32)
]}, align 4, !type !3, !type !4, !vcall_visibility !{i64 2}
!3 = !{i64 0, !"vfunc3.type"}
!4 = !{i64 4, !"vfunc4.type"}

; CHECK: @vtable2 = internal unnamed_addr constant { [2 x i32] } { [2 x i32] [
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
; CHECK-SAME: i32 0
; CHECK-SAME: ] }, align 4, !type !3, !type !4, !vcall_visibility !2

; (1) vfunc1_live is referenced from @main, stays alive
define internal void @vfunc1_live() {
; CHECK: define internal void @vfunc1_live(
Expand All @@ -43,19 +29,9 @@ define internal void @vfunc2_dead() {
ret void
}

; (3) vfunc3_live_extern is referenced from @main, stays alive
; CHECK: declare void @vfunc3_live_extern
declare void @vfunc3_live_extern()

; (4) vfunc4_dead_extern is never referenced, gets removed and vtable slot is null'd
; CHECK-NOT: declare void @vfunc4_dead_extern
declare void @vfunc4_dead_extern()

define void @main() {
%1 = ptrtoint ptr @vtable to i64 ; to keep @vtable alive
%2 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc1.type")
%3 = ptrtoint ptr @vtable2 to i64 ; to keep @vtable2 alive
%4 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc3.type")
ret void
}

Expand Down
8 changes: 0 additions & 8 deletions llvm/test/Transforms/WholeProgramDevirt/Inputs/export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,14 @@ GlobalValueMap:
TypeTestAssumeVCalls:
- GUID: 14276520915468743435 # typeid1
Offset: 0
- GUID: 271751036925422857 # typeid1_rv
Offset: 0
TypeCheckedLoadVCalls:
- GUID: 15427464259790519041 # typeid2
Offset: 0
- GUID: 1146149264729288256 # typeid2_rv
Offset: 0
TypeTestAssumeConstVCalls:
- VFunc:
GUID: 3515965990081467659 # typeid3
Offset: 0
Args: [12, 24]
- VFunc:
GUID: 2777626534618191571 # typeid3_rv
Offset: 0
Args: [12, 24]
TypeCheckedLoadConstVCalls:
- VFunc:
GUID: 17525413373118030901 # typeid4
Expand Down
157 changes: 0 additions & 157 deletions llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,6 @@
; RUN: FileCheck --check-prefix=SUMMARY %s < %t

; SUMMARY: TypeIdMap:
; SUMMARY-NEXT: typeid1_rv:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unknown
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: BranchFunnel
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid2_rv:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unknown
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: Indir
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid3_rv:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unknown
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: BranchFunnel
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unknown
Expand Down Expand Up @@ -132,29 +93,6 @@ declare i32 @vf3_2(ptr %this, i32 %arg)
declare i32 @vf4_1(ptr %this, i32 %arg)
declare i32 @vf4_2(ptr %this, i32 %arg)

declare ptr @llvm.load.relative.i32(ptr, i32)

;; These are relative vtables equivalent to the ones above.
@vt1_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_1 to i64), i64 ptrtoint (ptr @vt1_1_rv to i64)) to i32)], !type !5
@vt1_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_2 to i64), i64 ptrtoint (ptr @vt1_2_rv to i64)) to i32)], !type !5

@vt2_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_1 to i64), i64 ptrtoint (ptr @vt2_1_rv to i64)) to i32)], !type !6
@vt2_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_2 to i64), i64 ptrtoint (ptr @vt2_2_rv to i64)) to i32)], !type !6
@vt2_3_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_3 to i64), i64 ptrtoint (ptr @vt2_3_rv to i64)) to i32)], !type !6
@vt2_4_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_4 to i64), i64 ptrtoint (ptr @vt2_4_rv to i64)) to i32)], !type !6
@vt2_5_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_5 to i64), i64 ptrtoint (ptr @vt2_5_rv to i64)) to i32)], !type !6
@vt2_6_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_6 to i64), i64 ptrtoint (ptr @vt2_6_rv to i64)) to i32)], !type !6
@vt2_7_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_7 to i64), i64 ptrtoint (ptr @vt2_7_rv to i64)) to i32)], !type !6
@vt2_8_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_8 to i64), i64 ptrtoint (ptr @vt2_8_rv to i64)) to i32)], !type !6
@vt2_9_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_9 to i64), i64 ptrtoint (ptr @vt2_9_rv to i64)) to i32)], !type !6
@vt2_10_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_10 to i64), i64 ptrtoint (ptr @vt2_10_rv to i64)) to i32)], !type !6
@vt2_11_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_11 to i64), i64 ptrtoint (ptr @vt2_11_rv to i64)) to i32)], !type !6

@vt3_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_1 to i64), i64 ptrtoint (ptr @vt3_1_rv to i64)) to i32)], !type !7
@vt3_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_2 to i64), i64 ptrtoint (ptr @vt3_2_rv to i64)) to i32)], !type !7

@vt4_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_1 to i64), i64 ptrtoint (ptr @vt4_1_rv to i64)) to i32)], !type !8
@vt4_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_2 to i64), i64 ptrtoint (ptr @vt4_2_rv to i64)) to i32)], !type !8


; CHECK-LABEL: define i32 @fn1
Expand All @@ -170,19 +108,6 @@ define i32 @fn1(ptr %obj) #0 {
ret i32 %result
}

; CHECK-LABEL: define i32 @fn1_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn1_rv(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1)
%result = call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
ret i32 %result
}

; CHECK-LABEL: define i32 @fn2
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn2(ptr %obj) #0 {
Expand All @@ -195,18 +120,6 @@ define i32 @fn2(ptr %obj) #0 {
ret i32 %result
}

; CHECK-LABEL: define i32 @fn2_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn2_rv(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: call i32 %
%result = call i32 %fptr(ptr %obj, i32 1)
ret i32 %result
}

; CHECK-LABEL: define i32 @fn3
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn3(ptr %obj) #0 {
Expand All @@ -220,75 +133,10 @@ define i32 @fn3(ptr %obj) #0 {
ret i32 %result
}

; CHECK-LABEL: define i32 @fn3_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn3_rv(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !9)
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; RETP: call i32 @branch_funnel.1(ptr
; NORETP: call i32 %
%result = call i32 %fptr(ptr %obj, i32 1)
ret i32 %result
}

; CHECK-LABEL: define i32 @fn4
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn4(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr @vt1_1
; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
%result = call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
ret i32 %result
}

; CHECK-LABEL: define i32 @fn4_cpy
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn4_cpy(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr @vt1_1
; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
%result = call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
ret i32 %result
}

; CHECK-LABEL: define i32 @fn4_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn4_rv(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
%result = call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
ret i32 %result
}

; CHECK-LABEL: define i32 @fn4_rv_cpy
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
define i32 @fn4_rv_cpy(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
%result = call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
ret i32 %result
}

; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(ptr nest %0, ...)
; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2, ptr {{(nonnull )?}}@vf1_2, ...)

; CHECK-LABEL: define hidden void @__typeid_typeid1_rv_0_branch_funnel(ptr nest %0, ...)
; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1_rv, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2_rv, ptr {{(nonnull )?}}@vf1_2, ...)

; CHECK: define internal void @branch_funnel(ptr
; CHECK: define internal void @branch_funnel.1(ptr

declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)
Expand All @@ -298,10 +146,5 @@ declare void @llvm.assume(i1)
!2 = !{i32 0, !"typeid3"}
!3 = !{i32 0, !4}
!4 = distinct !{}
!5 = !{i32 0, !"typeid1_rv"}
!6 = !{i32 0, !"typeid2_rv"}
!7 = !{i32 0, !"typeid3_rv"}
!8 = !{i32 0, !9}
!9 = distinct !{}

attributes #0 = { "target-features"="+retpoline" }
45 changes: 0 additions & 45 deletions llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ target triple = "x86_64-unknown-linux-gnu"
; CHECK: private constant { [8 x i8], [1 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x ptr] [ptr @vf2], [0 x i8] zeroinitializer }, !type [[T8]]
; CHECK: private constant { [8 x i8], [1 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\01", [1 x ptr] [ptr @vf4], [0 x i8] zeroinitializer }, !type [[T8]]
; CHECK: private constant { [8 x i8], [1 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x ptr] [ptr @vf8], [0 x i8] zeroinitializer }, !type [[T8]]
; CHECK: private constant { [4 x i8], [1 x i32], [0 x i8] } { [4 x i8] c"\00\00\00\01", [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1 to i64), i64 ptrtoint (ptr @vt1_rv to i64)) to i32)], [0 x i8] zeroinitializer }, align 4, !type [[T4:![0-9]+]]
; CHECK: private constant { [4 x i8], [1 x i32], [0 x i8] } { [4 x i8] c"\00\00\00\02", [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2 to i64), i64 ptrtoint (ptr @vt2_rv to i64)) to i32)], [0 x i8] zeroinitializer }, align 4, !type [[T4]]
; CHECK: private constant { [4 x i8], [1 x i32], [0 x i8] } { [4 x i8] c"\00\00\00\01", [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4 to i64), i64 ptrtoint (ptr @vt4_rv to i64)) to i32)], [0 x i8] zeroinitializer }, align 4, !type [[T4]]
; CHECK: private constant { [4 x i8], [1 x i32], [0 x i8] } { [4 x i8] c"\00\00\00\02", [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf8 to i64), i64 ptrtoint (ptr @vt8_rv to i64)) to i32)], [0 x i8] zeroinitializer }, align 4, !type [[T4]]

@vt1 = constant [1 x ptr] [ptr @vf1], !type !0
@vt2 = constant [1 x ptr] [ptr @vf2], !type !0
Expand Down Expand Up @@ -65,49 +61,8 @@ define i1 @call2(ptr %obj) {
ret i1 %result
}

declare ptr @llvm.load.relative.i32(ptr, i32)

@vt1_rv = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1 to i64), i64 ptrtoint (ptr @vt1_rv to i64)) to i32)
], align 4, !type !1
@vt2_rv = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2 to i64), i64 ptrtoint (ptr @vt2_rv to i64)) to i32)
], align 4, !type !1
@vt4_rv = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4 to i64), i64 ptrtoint (ptr @vt4_rv to i64)) to i32)
], align 4, !type !1
@vt8_rv = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf8 to i64), i64 ptrtoint (ptr @vt8_rv to i64)) to i32)
], align 4, !type !1

; CHECK: define i1 @call3
define i1 @call3(ptr %obj) {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: getelementptr {{.*}} -1
; CHECK: and {{.*}}, 1
%result = call i1 %fptr(ptr %obj, i32 5)
ret i1 %result
}

; CHECK: define i1 @call4
define i1 @call4(ptr %obj) {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: getelementptr {{.*}} -1
; CHECK: and {{.*}}, 2
%result = call i1 %fptr(ptr %obj, i32 10)
ret i1 %result
}

declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)

; CHECK: [[T8]] = !{i32 8, !"typeid"}
; CHECK: [[T4]] = !{i32 4, !"typeid2"}
!0 = !{i32 0, !"typeid"}
!1 = !{i32 0, !"typeid2"}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

; CHECK: remark: <unknown>:0:0: single-impl: devirtualized a call to vf
; CHECK: remark: <unknown>:0:0: single-impl: devirtualized a call to vf
; CHECK: remark: <unknown>:0:0: devirtualized vf
; CHECK-NOT: devirtualized
Expand Down Expand Up @@ -34,31 +33,7 @@ trap:
unreachable
}

@vt3 = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf to i64), i64 ptrtoint (ptr @vt3 to i64)) to i32)
], align 4, !type !1

; CHECK: define void @call2
define void @call2(ptr %obj) {
%vtable = load ptr, ptr %obj
%pair = call {ptr, i1} @llvm.type.checked.load(ptr %vtable, i32 0, metadata !"typeid2")
%fptr = extractvalue {ptr, i1} %pair, 0
%p = extractvalue {ptr, i1} %pair, 1
; CHECK: br i1 true,
br i1 %p, label %cont, label %trap

cont:
; CHECK: call void @vf(
call void %fptr(ptr %obj)
ret void

trap:
call void @llvm.trap()
unreachable
}

declare {ptr, i1} @llvm.type.checked.load(ptr, i32, metadata)
declare void @llvm.trap()

!0 = !{i32 0, !"typeid"}
!1 = !{i32 0, !"typeid2"}
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,7 @@ define void @call(ptr %obj) {
ret void
}

declare ptr @llvm.load.relative.i32(ptr, i32)

@vt3 = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf to i64), i64 ptrtoint (ptr @vt3 to i64)) to i32)
], align 4, !type !1

; CHECK: define void @call2
define void @call2(ptr %obj) {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%p2 = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p2)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: call void @vf(
call void %fptr(ptr %obj)
ret void
}

declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)

!0 = !{i32 0, !"typeid"}
!1 = !{i32 0, !"typeid2"}
47 changes: 1 addition & 46 deletions llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

; CHECK: remark: devirt-single.cc:30:32: single-impl: devirtualized a call to vf
; CHECK: remark: devirt-single.cc:41:32: single-impl: devirtualized a call to vf
; CHECK: remark: devirt-single.cc:51:32: single-impl: devirtualized a call to vf
; CHECK: remark: devirt-single.cc:13:0: devirtualized vf
; CHECK-NOT: devirtualized

Expand All @@ -30,41 +28,6 @@ define void @call(ptr %obj) #1 !dbg !5 {
ret void
}

declare ptr @llvm.load.relative.i32(ptr, i32)

@vt3 = private unnamed_addr constant [1 x i32] [
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf to i64), i64 ptrtoint (ptr @vt3 to i64)) to i32)
], align 4, !type !11

; CHECK: define void @call2
define void @call2(ptr %obj) #1 !dbg !9 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: call void @vf(
call void %fptr(ptr %obj), !dbg !10
ret void
}

@_ZTV1A.local = private unnamed_addr constant { [3 x i32] } { [3 x i32] [
i32 0, ; offset to top
i32 0, ; rtti
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32) ; vfunc offset
] }, align 4, !type !14

; CHECK: define void @call3
define void @call3(ptr %obj) #1 !dbg !12 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 8)
; CHECK: call void @vf(
call void %fptr(ptr %obj), !dbg !13
ret void
}


declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)

Expand All @@ -82,13 +45,5 @@ declare void @llvm.assume(i1)
!7 = distinct !DISubprogram(name: "vf", linkageName: "_ZN3vt12vfEv", scope: !1, file: !1, line: 13, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false, unit: !0)
!8 = !{i32 0, !"typeid"}

!9 = distinct !DISubprogram(name: "call2", linkageName: "_Z5call2Pv", scope: !1, file: !1, line: 40, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0)
!10 = !DILocation(line: 41, column: 32, scope: !9)
!11 = !{i32 0, !"typeid2"}

!12 = distinct !DISubprogram(name: "call3", linkageName: "_Z5call3Pv", scope: !1, file: !1, line: 50, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0)
!13 = !DILocation(line: 51, column: 32, scope: !12)
!14 = !{i32 0, !"typeid3"}

; CHECK: 1 wholeprogramdevirt - Number of whole program devirtualization targets
; CHECK: 3 wholeprogramdevirt - Number of single implementation devirtualizations
; CHECK: 1 wholeprogramdevirt - Number of single implementation devirtualizations
16 changes: 0 additions & 16 deletions llvm/test/Transforms/WholeProgramDevirt/pointer-vtable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,7 @@ define void @call(ptr %obj) {
ret void
}

@vt2 = constant i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf to i64), i64 ptrtoint (ptr @vt2 to i64)) to i32), !type !1

declare ptr @llvm.load.relative.i32(ptr, i32)

; CHECK: define void @call2
define void @call2(ptr %obj) {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; CHECK: call void @vf(
call void %fptr(ptr %obj)
ret void
}

declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)

!0 = !{i32 0, !"typeid"}
!1 = !{i32 0, !"typeid2"}