diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2016-06-25 00:23:04 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2016-06-25 00:23:04 +0000 |
commit | 0312f614b1bfdad55c1832ee37d6d4b738ea70cf (patch) | |
tree | fe32499f559708bbe83f63a35aa420c91b882594 /llvm/test/Transforms/WholeProgramDevirt | |
parent | 6ad3d05b681b36f6ecc98523257d154053e4116d (diff) | |
download | bcm5719-llvm-0312f614b1bfdad55c1832ee37d6d4b738ea70cf.tar.gz bcm5719-llvm-0312f614b1bfdad55c1832ee37d6d4b738ea70cf.zip |
IR: Introduce llvm.type.checked.load intrinsic.
This intrinsic safely loads a function pointer from a virtual table pointer
using type metadata. This intrinsic is used to implement control flow integrity
in conjunction with virtual call optimization. The virtual call optimization
pass will optimize away llvm.type.checked.load intrinsics associated with
devirtualized calls, thereby removing the type check in cases where it is
not needed to enforce the control flow integrity constraint.
This patch also introduces the capability to copy type metadata between
global variables, and teaches the virtual call optimization pass to do so.
Differential Revision: http://reviews.llvm.org/D21121
llvm-svn: 273756
Diffstat (limited to 'llvm/test/Transforms/WholeProgramDevirt')
6 files changed, 257 insertions, 12 deletions
diff --git a/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll b/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll index 08047033aef..f65e4132738 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll @@ -4,10 +4,10 @@ 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 } +; 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 }, !type [[T8:![0-9]+]] +; 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 }, !type [[T8]] +; 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 }, !type [[T8]] +; 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 }, !type [[T8]] @vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)], !type !0 @vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)], !type !0 @@ -73,4 +73,5 @@ define i1 @call2(i8* %obj) { declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) +; CHECK: [[T8]] = !{i32 8, !"typeid"} !0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-check.ll b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-check.ll new file mode 100644 index 00000000000..7c52f26ebea --- /dev/null +++ b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-check.ll @@ -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 (void (i8*)* @vf to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0 + +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* + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 0, metadata !"typeid") + %fptr = extractvalue {i8*, i1} %pair, 0 + %p = extractvalue {i8*, i1} %pair, 1 + ; CHECK: br i1 true, + br i1 %p, label %cont, label %trap + +cont: + %fptr_casted = bitcast i8* %fptr to void (i8*)* + ; CHECK: call void @vf( + call void %fptr_casted(i8* %obj) + ret void + +trap: + call void @llvm.trap() + unreachable +} + +declare {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata) +declare void @llvm.trap() + +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/expand-check.ll b/llvm/test/Transforms/WholeProgramDevirt/expand-check.ll new file mode 100644 index 00000000000..4effaba08b2 --- /dev/null +++ b/llvm/test/Transforms/WholeProgramDevirt/expand-check.ll @@ -0,0 +1,63 @@ +; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s + +; Test that we correctly expand the llvm.type.checked.load intrinsic in cases +; where we cannot devirtualize. + +target datalayout = "e-p:64:64" +target triple = "x86_64-unknown-linux-gnu" + +@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf1 to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf2 to i8*)], !type !0 + +define void @vf1(i8* %this) { + ret void +} + +define void @vf2(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* + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 0, metadata !"typeid") + %p = extractvalue {i8*, i1} %pair, 1 + ; CHECK: [[TT:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^,]*]], metadata !"typeid") + ; CHECK: br i1 [[TT]], + br i1 %p, label %cont, label %trap + +cont: + ; CHECK: [[GEP:%[^ ]*]] = getelementptr i8, i8* [[VT]], i32 0 + ; CHECK: [[BC:%[^ ]*]] = bitcast i8* [[GEP]] to i8** + ; CHECK: [[LOAD:%[^ ]*]] = load i8*, i8** [[BC]] + ; CHECK: [[FPC:%[^ ]*]] = bitcast i8* [[LOAD]] to void (i8*)* + ; CHECK: call void [[FPC]] + %fptr = extractvalue {i8*, i1} %pair, 0 + %fptr_casted = bitcast i8* %fptr to void (i8*)* + call void %fptr_casted(i8* %obj) + ret void + +trap: + call void @llvm.trap() + unreachable +} + +; CHECK: define { i8*, i1 } @ret +define {i8*, i1} @ret(i8* %vtablei8) { + ; CHECK: [[GEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2:%[^,]*]], i32 1 + ; CHECK: [[BC2:%[^ ]*]] = bitcast i8* [[GEP2]] to i8** + ; CHECK: [[LOAD2:%[^ ]*]] = load i8*, i8** [[BC2]] + ; CHECK: [[TT2:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT2]], metadata !"typeid") + ; CHECK: [[I1:%[^ ]*]] = insertvalue { i8*, i1 } undef, i8* [[LOAD2]], 0 + ; CHECK: [[I2:%[^ ]*]] = insertvalue { i8*, i1 } %5, i1 [[TT2]], 1 + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 1, metadata !"typeid") + ; CHECK: ret { i8*, i1 } [[I2]] + ret {i8*, i1} %pair +} + +declare {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata) +declare void @llvm.trap() + +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll index f65b8a28288..530fe8aa89d 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll @@ -3,34 +3,35 @@ 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" +; 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", !type [[T8:![0-9]+]] @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", !type !0 -; 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 }{{$}} +; 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 }, !type [[T8]] @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*) ], !type !0 -; 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 }{{$}} +; 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 }, !type [[T8]] @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*) ], !type !0 -; 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 }{{$}} +; 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 }, !type [[T8]] @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*) ], !type !0 +; CHECK: @vt5 = {{.*}}, !type [[T0:![0-9]+]] @vt5 = constant [3 x i8*] [ i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), @@ -129,4 +130,7 @@ declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) declare void @__cxa_pure_virtual() +; CHECK: [[T8]] = !{i32 8, !"typeid"} +; CHECK: [[T0]] = !{i32 0, !"typeid"} + !0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll new file mode 100644 index 00000000000..4e219e238e5 --- /dev/null +++ b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll @@ -0,0 +1,136 @@ +; 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", !type [[T8:![0-9]+]] +@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", !type !0 + +; 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 }, !type [[T8]] +@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*) +], !type !0 + +; 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 }, !type [[T8]] +@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*) +], !type !0 + +; 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 }, !type [[T8]] +@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*) +], !type !0 + +; CHECK: @vt5 = {{.*}}, !type [[T0:![0-9]+]] +@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*) +], !type !0 + +; 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* + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 0, metadata !"typeid") + %fptr = extractvalue {i8*, i1} %pair, 0 + %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: [[AND1:%[^ ]*]] = and i1 [[VTCMP1]], true + %p = extractvalue {i8*, i1} %pair, 1 + %and = and i1 %result, %p + ; CHECK: ret i1 [[AND1]] + ret i1 %and +} + +; 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* + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 8, metadata !"typeid") + %fptr = extractvalue {i8*, i1} %pair, 0 + %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: [[AND2:%[^ ]*]] = and i1 [[VTCMP2]], true + %p = extractvalue {i8*, i1} %pair, 1 + %and = and i1 %result, %p + ; CHECK: ret i1 [[AND2]] + ret i1 %and +} + +; 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* + %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 16, metadata !"typeid") + %fptr = extractvalue {i8*, i1} %pair, 0 + %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 {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata) +declare void @llvm.assume(i1) +declare void @__cxa_pure_virtual() + +; CHECK: [[T8]] = !{i32 8, !"typeid"} +; CHECK: [[T0]] = !{i32 0, !"typeid"} + +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll index 04c89ddb026..75ec6ba95ef 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll @@ -3,7 +3,7 @@ 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" } +; 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" }, !type [[T8:![0-9]+]] @vt1 = constant [4 x i8*] [ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -11,14 +11,14 @@ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*) ], !type !1 -; 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" } +; 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" }, !type [[T0:![0-9]+]] @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*) ], !type !0 -; 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" } +; 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" }, !type [[T8]] @vt3 = constant [4 x i8*] [ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -26,7 +26,7 @@ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*) ], !type !1 -; 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" } +; 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" }, !type [[T0]] @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -124,5 +124,8 @@ define i32 @call3(i8* %obj) { declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) +; CHECK: [[T8]] = !{i32 8, !"typeid"} +; CHECK: [[T0]] = !{i32 0, !"typeid"} + !0 = !{i32 0, !"typeid"} !1 = !{i32 8, !"typeid"} |