WholeProgramDevirt: Teach the pass to handle structs of arrays.

This will become necessary in some cases once D22296 lands.

llvm-svn: 289165
diff --git a/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll
index 97445ef..4885be7 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll
@@ -3,14 +3,15 @@
 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*)], !type !0
+@vt1 = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)], !type !0
+@vt2 = global i8* bitcast (void (i8*)* @vf to i8*), !type !1
 
 define void @vf(i8* %this) {
   ret void
 }
 
-; CHECK: define void @unaligned
-define void @unaligned(i8* %obj) {
+; CHECK: define void @unaligned1
+define void @unaligned1(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*
@@ -25,6 +26,22 @@
   ret void
 }
 
+; CHECK: define void @unaligned2
+define void @unaligned2(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.type.test(i8* %vtablei8, metadata !"typeid2")
+  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*]**
@@ -61,3 +78,4 @@
 declare void @llvm.assume(i1)
 
 !0 = !{i32 0, !"typeid"}
+!1 = !{i32 0, !"typeid2"}
diff --git a/llvm/test/Transforms/WholeProgramDevirt/non-aggregate-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/pointer-vtable.ll
similarity index 96%
rename from llvm/test/Transforms/WholeProgramDevirt/non-aggregate-vtable.ll
rename to llvm/test/Transforms/WholeProgramDevirt/pointer-vtable.ll
index e9c2db7..5e76a5a 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/non-aggregate-vtable.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/pointer-vtable.ll
@@ -19,7 +19,7 @@
   %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 %
+  ; CHECK: call void @vf(
   call void %fptr_casted(i8* %obj)
   ret void
 }
diff --git a/llvm/test/Transforms/WholeProgramDevirt/soa-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/soa-vtable.ll
new file mode 100644
index 0000000..3b6afc5
--- /dev/null
+++ b/llvm/test/Transforms/WholeProgramDevirt/soa-vtable.ll
@@ -0,0 +1,52 @@
+; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s
+
+target datalayout = "e-p:64:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%vtTy = type { [2 x void (i8*)*], [2 x void (i8*)*] }
+
+@vt = constant %vtTy { [2 x void (i8*)*] [void (i8*)* null, void (i8*)* @vf1], [2 x void (i8*)*] [void (i8*)* null, void (i8*)* @vf2] }, !type !0, !type !1
+
+define void @vf1(i8* %this) {
+  ret void
+}
+
+define void @vf2(i8* %this) {
+  ret void
+}
+
+; CHECK: define void @call1
+define void @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.type.test(i8* %vtablei8, metadata !"typeid1")
+  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 @vf1(
+  call void %fptr_casted(i8* %obj)
+  ret void
+}
+
+; CHECK: define void @call2
+define void @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.type.test(i8* %vtablei8, metadata !"typeid2")
+  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 @vf2(
+  call void %fptr_casted(i8* %obj)
+  ret void
+}
+
+declare i1 @llvm.type.test(i8*, metadata)
+declare void @llvm.assume(i1)
+
+!0 = !{i32 8, !"typeid1"}
+!1 = !{i32 24, !"typeid2"}