| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)] | ||
|
|
||
| define void @vf(i8* %this) { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @unaligned | ||
| define void @unaligned(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr i8, i8* %vtablei8, i32 1 | ||
| %fptrptr_casted = bitcast i8* %fptrptr to i8** | ||
| %fptr = load i8*, i8** %fptrptr_casted | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void % | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @outofbounds | ||
| define void @outofbounds(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr i8, i8* %vtablei8, i32 16 | ||
| %fptrptr_casted = bitcast i8* %fptrptr to i8** | ||
| %fptr = load i8*, i8** %fptrptr_casted | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void % | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @nonfunction | ||
| define void @nonfunction(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr i8, i8* %vtablei8, i32 0 | ||
| %fptrptr_casted = bitcast i8* %fptrptr to i8** | ||
| %fptr = load i8*, i8** %fptrptr_casted | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void % | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [2 x i8*]* @vt, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\01", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)], [0 x i8] zeroinitializer } | ||
| ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)], [0 x i8] zeroinitializer } | ||
| ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\01", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)], [0 x i8] zeroinitializer } | ||
| ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)], [0 x i8] zeroinitializer } | ||
|
|
||
| @vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)] | ||
| @vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)] | ||
| @vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)] | ||
| @vt8 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)] | ||
|
|
||
| define i1 @vf1(i8* %this, i32 %arg) readnone { | ||
| %and = and i32 %arg, 1 | ||
| %cmp = icmp ne i32 %and, 0 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
| define i1 @vf2(i8* %this, i32 %arg) readnone { | ||
| %and = and i32 %arg, 2 | ||
| %cmp = icmp ne i32 %and, 0 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
| define i1 @vf4(i8* %this, i32 %arg) readnone { | ||
| %and = and i32 %arg, 4 | ||
| %cmp = icmp ne i32 %and, 0 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
| define i1 @vf8(i8* %this, i32 %arg) readnone { | ||
| %and = and i32 %arg, 8 | ||
| %cmp = icmp ne i32 %and, 0 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call1 | ||
| define i1 @call1(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*, i32)* | ||
| ; CHECK: getelementptr {{.*}} -1 | ||
| ; CHECK: and {{.*}}, 1 | ||
| %result = call i1 %fptr_casted(i8* %obj, i32 5) | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call2 | ||
| define i1 @call2(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*, i32)* | ||
| ; CHECK: getelementptr {{.*}} -1 | ||
| ; CHECK: and {{.*}}, 2 | ||
| %result = call i1 %fptr_casted(i8* %obj, i32 10) | ||
| ret i1 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !2 = !{!"bitset", [1 x i8*]* @vt4, i32 0} | ||
| !3 = !{!"bitset", [1 x i8*]* @vt8, i32 0} | ||
| !llvm.bitsets = !{!0, !1, !2, !3} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] | ||
| @vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] | ||
|
|
||
| define void @vf(i8* %this) { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @call | ||
| define void @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void @vf( | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0, !1} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt = constant i8* bitcast (void (i8*)* @vf to i8*) | ||
|
|
||
| define void @vf(i8* %this) { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @call | ||
| define void @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void % | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", i8** @vt, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt = global [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] | ||
|
|
||
| define void @vf(i8* %this) { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: define void @call | ||
| define void @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to void (i8*)* | ||
| ; CHECK: call void % | ||
| call void %fptr_casted(i8* %obj) | ||
| ret void | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] | ||
| @vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this) readnone { | ||
| ret i32 123 | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this) readnone { | ||
| ret i32 123 | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call | ||
| define i32 @call(i8* %obj) personality i8* undef { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*)* | ||
| ; CHECK: br label %[[RET:[0-9A-Za-z]*]] | ||
| %result = invoke i32 %fptr_casted(i8* %obj) to label %ret unwind label %unwind | ||
|
|
||
| unwind: | ||
| %x = landingpad i32 cleanup | ||
| unreachable | ||
|
|
||
| ret: | ||
| ; CHECK: [[RET]]: | ||
| ; CHECK-NEXT: ret i32 123 | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0, !1} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] | ||
| @vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this) readnone { | ||
| ret i32 123 | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this) readnone { | ||
| ret i32 123 | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call | ||
| define i32 @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*)* | ||
| %result = call i32 %fptr_casted(i8* %obj) | ||
| ; CHECK-NOT: call | ||
| ; CHECK: ret i32 123 | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0, !1} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)] | ||
| @vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)] | ||
| @vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)] | ||
| @vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)] | ||
|
|
||
| define i1 @vf0(i8* %this) readnone { | ||
| ret i1 0 | ||
| } | ||
|
|
||
| define i1 @vf1(i8* %this) readnone { | ||
| ret i1 1 | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call1 | ||
| define i1 @call1(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| ; CHECK: [[VT1:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset1") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[RES1:%[^ ]*]] = icmp eq i8* [[VT1]], bitcast ([1 x i8*]* @vt3 to i8*) | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i1 [[RES1]] | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call2 | ||
| define i1 @call2(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| ; CHECK: [[VT2:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset2") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[RES1:%[^ ]*]] = icmp ne i8* [[VT1]], bitcast ([1 x i8*]* @vt2 to i8*) | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ret i1 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset1", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset1", [1 x i8*]* @vt2, i32 0} | ||
| !2 = !{!"bitset1", [1 x i8*]* @vt3, i32 0} | ||
| !3 = !{!"bitset2", [1 x i8*]* @vt2, i32 0} | ||
| !4 = !{!"bitset2", [1 x i8*]* @vt3, i32 0} | ||
| !5 = !{!"bitset2", [1 x i8*]* @vt4, i32 0} | ||
| !llvm.bitsets = !{!0, !1, !2, !3, !4, !5} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this, i32 %arg) { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this, i32 %arg) { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call | ||
| define i32 @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*, i32)* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted(i8* %obj, i32 1) | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i32 ()* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i32 ()* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1() readnone { | ||
| ret i32 1 | ||
| } | ||
|
|
||
| define i32 @vf2() readnone { | ||
| ret i32 2 | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call | ||
| define i32 @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 ()* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted() | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this, i32 %arg) readnone { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this, i32 %arg) readnone { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| ; CHECK: define void @call | ||
| define void @call(i8* %obj, i32 %arg) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*, i32)* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted(i8* %obj, i32 %arg) | ||
| ret void | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf2 to i8*)] | ||
|
|
||
| define i128 @vf1(i8* %this, i128 %arg) readnone { | ||
| ret i128 %arg | ||
| } | ||
|
|
||
| define i128 @vf2(i8* %this, i128 %arg) readnone { | ||
| ret i128 %arg | ||
| } | ||
|
|
||
| ; CHECK: define i128 @call | ||
| define i128 @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i128 (i8*, i128)* | ||
| ; CHECK: call i128 % | ||
| %result = call i128 %fptr_casted(i8* %obj, i128 1) | ||
| ret i128 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this, i32 %arg) readnone { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this, i32 %arg) readnone { | ||
| ret i32 %arg | ||
| } | ||
|
|
||
| ; CHECK: define i32 @bad_arg_type | ||
| define i32 @bad_arg_type(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*, i64)* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted(i8* %obj, i64 1) | ||
| ret i32 %result | ||
| } | ||
|
|
||
| ; CHECK: define i32 @bad_arg_count | ||
| define i32 @bad_arg_count(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*, i64, i64)* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted(i8* %obj, i64 1, i64 2) | ||
| ret i32 %result | ||
| } | ||
|
|
||
| ; CHECK: define i64 @bad_return_type | ||
| define i64 @bad_return_type(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i64 (i8*, i32)* | ||
| ; CHECK: call i64 % | ||
| %result = call i64 %fptr_casted(i8* %obj, i32 1) | ||
| ret i64 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| @vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] | ||
| @vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] | ||
|
|
||
| define i32 @vf1(i8* %this) readnone { | ||
| %this_int = ptrtoint i8* %this to i32 | ||
| ret i32 %this_int | ||
| } | ||
|
|
||
| define i32 @vf2(i8* %this) readnone { | ||
| %this_int = ptrtoint i8* %this to i32 | ||
| ret i32 %this_int | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call | ||
| define i32 @call(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [1 x i8*]** | ||
| %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr | ||
| %vtablei8 = bitcast [1 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*)* | ||
| ; CHECK: call i32 % | ||
| %result = call i32 %fptr_casted(i8* %obj) | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} | ||
| !llvm.bitsets = !{!0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| ; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec" | ||
| @vt1 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf1i32 to i8*) | ||
| ], section "vt1sec" | ||
|
|
||
| ; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }{{$}} | ||
| @vt2 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf2i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }{{$}} | ||
| @vt3 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf3i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }{{$}} | ||
| @vt4 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf4i32 to i8*) | ||
| ] | ||
|
|
||
| @vt5 = constant [3 x i8*] [ | ||
| i8* bitcast (void ()* @__cxa_pure_virtual to i8*), | ||
| i8* bitcast (void ()* @__cxa_pure_virtual to i8*), | ||
| i8* bitcast (void ()* @__cxa_pure_virtual to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: @vt1 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT1DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT2DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt3 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT3DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt4 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT4DATA]], i32 0, i32 1) | ||
|
|
||
| define i1 @vf0i1(i8* %this) readnone { | ||
| ret i1 0 | ||
| } | ||
|
|
||
| define i1 @vf1i1(i8* %this) readnone { | ||
| ret i1 1 | ||
| } | ||
|
|
||
| define i32 @vf1i32(i8* %this) readnone { | ||
| ret i32 1 | ||
| } | ||
|
|
||
| define i32 @vf2i32(i8* %this) readnone { | ||
| ret i32 2 | ||
| } | ||
|
|
||
| define i32 @vf3i32(i8* %this) readnone { | ||
| ret i32 3 | ||
| } | ||
|
|
||
| define i32 @vf4i32(i8* %this) readnone { | ||
| ret i32 4 | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call1( | ||
| define i1 @call1(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i64 -5 | ||
| ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]] | ||
| ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2 | ||
| ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0 | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i1 [[VTCMP1]] | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call2( | ||
| define i1 @call2(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i64 -5 | ||
| ; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]] | ||
| ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1 | ||
| ; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0 | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i1 [[VTCMP2]] | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call3( | ||
| define i32 @call3(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*)* | ||
| ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i64 -4 | ||
| ; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32* | ||
| ; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]] | ||
| %result = call i32 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i32 [[VTLOAD3]] | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
| declare void @__cxa_pure_virtual() | ||
|
|
||
| !0 = !{!"bitset", [3 x i8*]* @vt1, i32 0} | ||
| !1 = !{!"bitset", [3 x i8*]* @vt2, i32 0} | ||
| !2 = !{!"bitset", [3 x i8*]* @vt3, i32 0} | ||
| !3 = !{!"bitset", [3 x i8*]* @vt4, i32 0} | ||
| !4 = !{!"bitset", [3 x i8*]* @vt5, i32 0} | ||
| !llvm.bitsets = !{!0, !1, !2, !3, !4} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| ; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s | ||
|
|
||
| target datalayout = "e-p:64:64" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| ; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [8 x i8] c"\01\00\00\00\01\00\00\00" } | ||
| @vt1 = constant [4 x i8*] [ | ||
| i8* null, | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf1i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [8 x i8] c"\02\00\00\00\02\00\00\00" } | ||
| @vt2 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf2i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [8 x i8] c"\03\00\00\00\01\00\00\00" } | ||
| @vt3 = constant [4 x i8*] [ | ||
| i8* null, | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf3i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [8 x i8] c"\04\00\00\00\02\00\00\00" } | ||
| @vt4 = constant [3 x i8*] [ | ||
| i8* bitcast (i1 (i8*)* @vf1i1 to i8*), | ||
| i8* bitcast (i1 (i8*)* @vf0i1 to i8*), | ||
| i8* bitcast (i32 (i8*)* @vf4i32 to i8*) | ||
| ] | ||
|
|
||
| ; CHECK: @vt1 = alias [4 x i8*], getelementptr inbounds ({ [0 x i8], [4 x i8*], [8 x i8] }, { [0 x i8], [4 x i8*], [8 x i8] }* [[VT1DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [0 x i8], [3 x i8*], [8 x i8] }, { [0 x i8], [3 x i8*], [8 x i8] }* [[VT2DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt3 = alias [4 x i8*], getelementptr inbounds ({ [0 x i8], [4 x i8*], [8 x i8] }, { [0 x i8], [4 x i8*], [8 x i8] }* [[VT3DATA]], i32 0, i32 1) | ||
| ; CHECK: @vt4 = alias [3 x i8*], getelementptr inbounds ({ [0 x i8], [3 x i8*], [8 x i8] }, { [0 x i8], [3 x i8*], [8 x i8] }* [[VT4DATA]], i32 0, i32 1) | ||
|
|
||
| define i1 @vf0i1(i8* %this) readnone { | ||
| ret i1 0 | ||
| } | ||
|
|
||
| define i1 @vf1i1(i8* %this) readnone { | ||
| ret i1 1 | ||
| } | ||
|
|
||
| define i32 @vf1i32(i8* %this) readnone { | ||
| ret i32 1 | ||
| } | ||
|
|
||
| define i32 @vf2i32(i8* %this) readnone { | ||
| ret i32 2 | ||
| } | ||
|
|
||
| define i32 @vf3i32(i8* %this) readnone { | ||
| ret i32 3 | ||
| } | ||
|
|
||
| define i32 @vf4i32(i8* %this) readnone { | ||
| ret i32 4 | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call1( | ||
| define i1 @call1(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i64 28 | ||
| ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]] | ||
| ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2 | ||
| ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0 | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i1 [[VTCMP1]] | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i1 @call2( | ||
| define i1 @call2(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i1 (i8*)* | ||
| ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i64 28 | ||
| ; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]] | ||
| ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1 | ||
| ; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0 | ||
| %result = call i1 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i1 [[VTCMP2]] | ||
| ret i1 %result | ||
| } | ||
|
|
||
| ; CHECK: define i32 @call3( | ||
| define i32 @call3(i8* %obj) { | ||
| %vtableptr = bitcast i8* %obj to [3 x i8*]** | ||
| %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr | ||
| ; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* | ||
| %vtablei8 = bitcast [3 x i8*]* %vtable to i8* | ||
| %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") | ||
| call void @llvm.assume(i1 %p) | ||
| %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 | ||
| %fptr = load i8*, i8** %fptrptr | ||
| %fptr_casted = bitcast i8* %fptr to i32 (i8*)* | ||
| ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i64 24 | ||
| ; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32* | ||
| ; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]] | ||
| %result = call i32 %fptr_casted(i8* %obj) | ||
| ; CHECK: ret i32 [[VTLOAD3]] | ||
| ret i32 %result | ||
| } | ||
|
|
||
| declare i1 @llvm.bitset.test(i8*, metadata) | ||
| declare void @llvm.assume(i1) | ||
|
|
||
| !0 = !{!"bitset", [4 x i8*]* @vt1, i32 8} | ||
| !1 = !{!"bitset", [3 x i8*]* @vt2, i32 0} | ||
| !2 = !{!"bitset", [4 x i8*]* @vt3, i32 8} | ||
| !3 = !{!"bitset", [3 x i8*]* @vt4, i32 0} | ||
| !llvm.bitsets = !{!0, !1, !2, !3} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,5 @@ set(LLVM_LINK_COMPONENTS | |
|
|
||
| add_llvm_unittest(IPOTests | ||
| LowerBitSets.cpp | ||
| WholeProgramDevirt.cpp | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| //===- WholeProgramDevirt.cpp - Unit tests for whole-program devirt -------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/Transforms/IPO/WholeProgramDevirt.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace wholeprogramdevirt; | ||
|
|
||
| TEST(WholeProgramDevirt, findLowestOffset) { | ||
| VTableBits VT1; | ||
| VT1.ObjectSize = 8; | ||
| VT1.Before.BytesUsed = {1 << 0}; | ||
| VT1.After.BytesUsed = {1 << 1}; | ||
|
|
||
| VTableBits VT2; | ||
| VT2.ObjectSize = 8; | ||
| VT2.Before.BytesUsed = {1 << 1}; | ||
| VT2.After.BytesUsed = {1 << 0}; | ||
|
|
||
| BitSetInfo BS1{&VT1, 0}; | ||
| BitSetInfo BS2{&VT2, 0}; | ||
| VirtualCallTarget Targets[] = { | ||
| {&BS1, /*IsBigEndian=*/false}, | ||
| {&BS2, /*IsBigEndian=*/false}, | ||
| }; | ||
|
|
||
| EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); | ||
| EXPECT_EQ(66ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); | ||
|
|
||
| EXPECT_EQ(8ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); | ||
| EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); | ||
|
|
||
| BS1.Offset = 4; | ||
| EXPECT_EQ(33ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); | ||
| EXPECT_EQ(65ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); | ||
|
|
||
| EXPECT_EQ(40ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); | ||
| EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); | ||
|
|
||
| BS1.Offset = 8; | ||
| BS2.Offset = 8; | ||
| EXPECT_EQ(66ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); | ||
| EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); | ||
|
|
||
| EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); | ||
| EXPECT_EQ(8ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); | ||
|
|
||
| VT1.After.BytesUsed = {0xff, 0, 0, 0, 0xff}; | ||
| VT2.After.BytesUsed = {0xff, 1, 0, 0, 0}; | ||
| EXPECT_EQ(16ull, findLowestOffset(Targets, /*IsAfter=*/true, 16)); | ||
| EXPECT_EQ(40ull, findLowestOffset(Targets, /*IsAfter=*/true, 32)); | ||
| } | ||
|
|
||
| TEST(WholeProgramDevirt, setReturnValues) { | ||
| VTableBits VT1; | ||
| VT1.ObjectSize = 8; | ||
|
|
||
| VTableBits VT2; | ||
| VT2.ObjectSize = 8; | ||
|
|
||
| BitSetInfo BS1{&VT1, 0}; | ||
| BitSetInfo BS2{&VT2, 0}; | ||
| VirtualCallTarget Targets[] = { | ||
| {&BS1, /*IsBigEndian=*/false}, | ||
| {&BS2, /*IsBigEndian=*/false}, | ||
| }; | ||
|
|
||
| BS1.Offset = 4; | ||
| BS2.Offset = 4; | ||
|
|
||
| int64_t OffsetByte; | ||
| uint64_t OffsetBit; | ||
|
|
||
| Targets[0].RetVal = 1; | ||
| Targets[1].RetVal = 0; | ||
| setBeforeReturnValues(Targets, 32, 1, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(-5ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.Before.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.Before.BytesUsed); | ||
| EXPECT_EQ(std::vector<uint8_t>{0}, VT2.Before.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT2.Before.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 0; | ||
| Targets[1].RetVal = 1; | ||
| setBeforeReturnValues(Targets, 39, 1, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(-5ll, OffsetByte); | ||
| EXPECT_EQ(7ull, OffsetBit); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.Before.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x81}, VT1.Before.BytesUsed); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x80}, VT2.Before.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x81}, VT2.Before.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 12; | ||
| Targets[1].RetVal = 34; | ||
| setBeforeReturnValues(Targets, 40, 8, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(-6ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ((std::vector<uint8_t>{1, 12}), VT1.Before.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff}), VT1.Before.BytesUsed); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x80, 34}), VT2.Before.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff}), VT2.Before.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 56; | ||
| Targets[1].RetVal = 78; | ||
| setBeforeReturnValues(Targets, 48, 16, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(-8ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ((std::vector<uint8_t>{1, 12, 0, 56}), VT1.Before.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff, 0xff, 0xff}), | ||
| VT1.Before.BytesUsed); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x80, 34, 0, 78}), VT2.Before.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff, 0xff, 0xff}), | ||
| VT2.Before.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 1; | ||
| Targets[1].RetVal = 0; | ||
| setAfterReturnValues(Targets, 32, 1, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(4ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.After.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.After.BytesUsed); | ||
| EXPECT_EQ(std::vector<uint8_t>{0}, VT2.After.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT2.After.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 0; | ||
| Targets[1].RetVal = 1; | ||
| setAfterReturnValues(Targets, 39, 1, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(4ll, OffsetByte); | ||
| EXPECT_EQ(7ull, OffsetBit); | ||
| EXPECT_EQ(std::vector<uint8_t>{1}, VT1.After.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x81}, VT1.After.BytesUsed); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x80}, VT2.After.Bytes); | ||
| EXPECT_EQ(std::vector<uint8_t>{0x81}, VT2.After.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 12; | ||
| Targets[1].RetVal = 34; | ||
| setAfterReturnValues(Targets, 40, 8, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(5ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ((std::vector<uint8_t>{1, 12}), VT1.After.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff}), VT1.After.BytesUsed); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x80, 34}), VT2.After.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff}), VT2.After.BytesUsed); | ||
|
|
||
| Targets[0].RetVal = 56; | ||
| Targets[1].RetVal = 78; | ||
| setAfterReturnValues(Targets, 48, 16, OffsetByte, OffsetBit); | ||
| EXPECT_EQ(6ll, OffsetByte); | ||
| EXPECT_EQ(0ull, OffsetBit); | ||
| EXPECT_EQ((std::vector<uint8_t>{1, 12, 56, 0}), VT1.After.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff, 0xff, 0xff}), | ||
| VT1.After.BytesUsed); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x80, 34, 78, 0}), VT2.After.Bytes); | ||
| EXPECT_EQ((std::vector<uint8_t>{0x81, 0xff, 0xff, 0xff}), | ||
| VT2.After.BytesUsed); | ||
| } |