1 // RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o %t.ll -O1 -disable-llvm-passes -fms-extensions -fstrict-vtable-pointers 2 // RUN: %clang_cc1 %s -triple i686-pc-win32 -emit-llvm -o %t.ms.ll -O1 -disable-llvm-passes -fms-extensions -fstrict-vtable-pointers 3 // RUN: %clang_cc1 %s -triple=spirv64-amd-amdhsa -std=c++11 -emit-llvm -o %t.ll -O1 -disable-llvm-passes -fms-extensions -fstrict-vtable-pointers 4 // FIXME: Assume load should not require -fstrict-vtable-pointers 5 6 // RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s 7 // RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s 8 // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s 9 // RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s 10 // RUN: FileCheck --check-prefix=CHECK-MS --input-file=%t.ms.ll %s 11 // RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s 12 // RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s 13 // RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s 14 // RUN: FileCheck --check-prefix=CHECK9 --input-file=%t.ll %s 15 namespace test1 { 16 17 struct A { 18 A(); 19 virtual void foo(); 20 }; 21 22 struct B : A { 23 virtual void foo(); 24 }; 25 26 void g(A *a) { a->foo(); } 27 28 // CHECK1-LABEL: define{{.*}} void @_ZN5test14fooAEv() 29 // CHECK1: call{{.*}} void @_ZN5test11AC1Ev(ptr {{((addrspace(4)){0,1})}} 30 // CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr {{((addrspace(4)){0,1})}}{{.*}}%{{.*}} 31 // CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11AE, i32 0, i32 0, i32 2) 32 // CHECK1: call{{.*}} void @llvm.assume(i1 %[[CMP]]) 33 // CHECK1-LABEL: {{^}}} 34 35 void fooA() { 36 A a; 37 g(&a); 38 } 39 40 // CHECK1-LABEL: define{{.*}} void @_ZN5test14fooBEv() 41 // CHECK1: call{{.*}} void @_ZN5test11BC1Ev(ptr {{[^,]*}} %{{.*}}) 42 // CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr {{((addrspace(4)){0,1})}}{{.*}}%{{.*}} 43 // CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11BE, i32 0, i32 0, i32 2) 44 // CHECK1: call{{.*}} void @llvm.assume(i1 %[[CMP]]) 45 // CHECK1-LABEL: {{^}}} 46 47 void fooB() { 48 B b; 49 g(&b); 50 } 51 // there should not be any assumes in the ctor that calls base ctor 52 // CHECK1-LABEL: define linkonce_odr{{.*}} void @_ZN5test11BC2Ev(ptr 53 // CHECK1-NOT: @llvm.assume( 54 // CHECK1-LABEL: {{^}}} 55 } 56 namespace test2 { 57 struct A { 58 A(); 59 virtual void foo(); 60 }; 61 62 struct B { 63 B(); 64 virtual void bar(); 65 }; 66 67 struct C : A, B { 68 C(); 69 virtual void foo(); 70 }; 71 void g(A *a) { a->foo(); } 72 void h(B *b) { b->bar(); } 73 74 // CHECK2-LABEL: define{{.*}} void @_ZN5test24testEv() 75 // CHECK2: call{{.*}} void @_ZN5test21CC1Ev(ptr 76 // CHECK2: %[[VTABLE:.*]] = load ptr addrspace(1), ptr {{.*}} 77 // CHECK2: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, i32 0, i32 2) 78 // CHECK2: call{{.*}} void @llvm.assume(i1 %[[CMP]]) 79 80 // CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr {{((addrspace(4)){0,1})}}{{.*}}%{{.*}}, i64 8 81 // CHECK2: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr {{((addrspace(4)){0,1})}}{{.*}}%[[ADD_PTR]] 82 // CHECK2: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, i32 1, i32 2) 83 // CHECK2: call{{.*}} void @llvm.assume(i1 %[[CMP2]]) 84 85 // CHECK2: call{{.*}} void @_ZN5test21gEPNS_1AE( 86 // CHECK2-LABEL: {{^}}} 87 88 void test() { 89 C c; 90 g(&c); 91 h(&c); 92 } 93 } 94 95 namespace test3 { 96 struct A { 97 A(); 98 }; 99 100 struct B : A { 101 B(); 102 virtual void foo(); 103 }; 104 105 struct C : virtual A, B { 106 C(); 107 virtual void foo(); 108 }; 109 void g(B *a) { a->foo(); } 110 111 // CHECK3-LABEL: define{{.*}} void @_ZN5test34testEv() 112 // CHECK3: call{{.*}} void @_ZN5test31CC1Ev(ptr 113 // CHECK3: %[[CMP:.*]] = icmp eq ptr addrspace(1) %{{.*}}, getelementptr inbounds inrange(-24, 8) ({ [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test31CE, i32 0, i32 0, i32 3) 114 // CHECK3: call{{.*}} void @llvm.assume(i1 %[[CMP]]) 115 // CHECK3-LABLEL: } 116 void test() { 117 C c; 118 g(&c); 119 } 120 } // test3 121 122 namespace test4 { 123 struct A { 124 A(); 125 virtual void foo(); 126 }; 127 128 struct B : virtual A { 129 B(); 130 virtual void foo(); 131 }; 132 struct C : B { 133 C(); 134 virtual void foo(); 135 }; 136 137 void g(C *c) { c->foo(); } 138 139 // CHECK4-LABEL: define{{.*}} void @_ZN5test44testEv() 140 // CHECK4: call{{.*}} void @_ZN5test41CC1Ev(ptr 141 // CHECK4: %[[VTABLE:.*]] = load ptr addrspace(1), ptr {{((addrspace(4)){0,1})}}{{.*}}%{{.*}} 142 // CHECK4: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, i32 0, i32 4) 143 // CHECK4: call{{.*}} void @llvm.assume(i1 %[[CMP]] 144 145 // CHECK4: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr {{((addrspace(4)){0,1})}}{{.*}}%{{.*}} 146 // CHECK4: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, i32 0, i32 4) 147 // CHECK4: call{{.*}} void @llvm.assume(i1 %[[CMP2]]) 148 // CHECK4-LABEL: {{^}}} 149 150 void test() { 151 C c; 152 g(&c); 153 } 154 } // test4 155 156 namespace testMS { 157 158 struct __declspec(novtable) S { 159 virtual void foo(); 160 }; 161 162 void g(S &s) { s.foo(); } 163 164 // if struct has novtable specifier, then we can't generate assumes 165 // CHECK-MS-LABEL: define dso_local void @"?test@testMS@@YAXXZ"() 166 // CHECK-MS: call x86_thiscallcc noundef ptr @"??0S@testMS@@QAE@XZ"( 167 // CHECK-MS-NOT: @llvm.assume 168 // CHECK-MS-LABEL: {{^}}} 169 170 void test() { 171 S s; 172 g(s); 173 } 174 175 } // testMS 176 177 namespace test6 { 178 struct A { 179 A(); 180 virtual void foo(); 181 virtual ~A() {} 182 }; 183 struct B : A { 184 B(); 185 }; 186 // FIXME: Because A's vtable is external, and no virtual functions are hidden, 187 // it's safe to generate assumption loads. 188 // CHECK6-LABEL: define{{.*}} void @_ZN5test61gEv() 189 // CHECK6: call{{.*}} void @_ZN5test61AC1Ev( 190 // CHECK6-NOT: call void @llvm.assume( 191 192 // We can't emit assumption loads for B, because if we would refer to vtable 193 // it would refer to functions that will not be able to find (like implicit 194 // inline destructor). 195 196 // CHECK6-LABEL: call{{.*}} void @_ZN5test61BC1Ev( 197 // CHECK6-NOT: call void @llvm.assume( 198 // CHECK6-LABEL: {{^}}} 199 void g() { 200 A *a = new A; 201 B *b = new B; 202 } 203 } 204 205 namespace test7 { 206 // Because A's key function is defined here, vtable is generated in this TU 207 // CHECK7: @_ZTVN5test71AE ={{.*}} unnamed_addr addrspace(1) constant 208 struct A { 209 A(); 210 virtual void foo(); 211 virtual void bar(); 212 }; 213 void A::foo() {} 214 215 // CHECK7-LABEL: define{{.*}} void @_ZN5test71gEv() 216 // CHECK7: call{{.*}} void @_ZN5test71AC1Ev( 217 // CHECK7: call{{.*}} void @llvm.assume( 218 // CHECK7-LABEL: {{^}}} 219 void g() { 220 A *a = new A(); 221 a->bar(); 222 } 223 } 224 225 namespace test8 { 226 227 struct A { 228 virtual void foo(); 229 virtual void bar(); 230 }; 231 232 // CHECK8-DAG: @_ZTVN5test81BE = available_externally unnamed_addr addrspace(1) constant 233 struct B : A { 234 B(); 235 void foo(); 236 void bar(); 237 }; 238 239 // CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr addrspace(1) constant 240 struct C : A { 241 C(); 242 void bar(); 243 void foo() {} 244 }; 245 inline void C::bar() {} 246 247 struct D : A { 248 D(); 249 void foo(); 250 void inline bar(); 251 }; 252 void D::bar() {} 253 254 // CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr addrspace(1) constant 255 struct E : A { 256 E(); 257 }; 258 259 // CHECK8-LABEL: define{{.*}} void @_ZN5test81bEv() 260 // CHECK8: call{{.*}} void @llvm.assume( 261 // CHECK8-LABEL: {{^}}} 262 void b() { 263 B b; 264 b.bar(); 265 } 266 267 // FIXME: C has inline virtual functions which prohibits as from generating 268 // assumption loads, but because vtable is generated in this TU (key function 269 // defined here) it would be correct to refer to it. 270 // CHECK8-LABEL: define{{.*}} void @_ZN5test81cEv() 271 // CHECK8-NOT: call void @llvm.assume( 272 // CHECK8-LABEL: {{^}}} 273 void c() { 274 C c; 275 c.bar(); 276 } 277 278 // FIXME: We could generate assumption loads here. 279 // CHECK8-LABEL: define{{.*}} void @_ZN5test81dEv() 280 // CHECK8-NOT: call void @llvm.assume( 281 // CHECK8-LABEL: {{^}}} 282 void d() { 283 D d; 284 d.bar(); 285 } 286 287 // CHECK8-LABEL: define{{.*}} void @_ZN5test81eEv() 288 // CHECK8: call{{.*}} void @llvm.assume( 289 // CHECK8-LABEL: {{^}}} 290 void e() { 291 E e; 292 e.bar(); 293 } 294 } 295 296 namespace test9 { 297 298 struct S { 299 S(); 300 __attribute__((visibility("hidden"))) virtual void doStuff(); 301 }; 302 303 // CHECK9-LABEL: define{{.*}} void @_ZN5test94testEv() 304 // CHECK9-NOT: @llvm.assume( 305 // CHECK9: } 306 void test() { 307 S *s = new S(); 308 s->doStuff(); 309 delete s; 310 } 311 } 312 313