1; Test to ensure that devirtualization will succeed when there is an earlier 2; type test also corresponding to the same vtable (when indicated by invariant 3; load metadata), that provides a more refined type. This could happen in 4; after inlining into a caller passing a derived type. 5 6; RUN: opt -module-summary %s -o %t.o 7; RUN: llvm-lto2 run -o %t.out %t.o \ 8; RUN: -pass-remarks=wholeprogramdevirt \ 9; RUN: -r %t.o,_ZN1A3fooEv,px \ 10; RUN: -r %t.o,_ZN1B3fooEv,px \ 11; RUN: -r %t.o,_Z6callerP1B,px \ 12; RUN: -r %t.o,_ZTV1A,px \ 13; RUN: -r %t.o,_ZTV1B,px \ 14; RUN: -save-temps 2>&1 | FileCheck %s 15 16; CHECK-COUNT-2: single-impl: devirtualized a call to _ZN1B3fooEv 17 18; RUN: llvm-dis %t.out.1.4.opt.bc -o - | FileCheck %s --check-prefix=IR 19; IR-NOT: tail call void % 20 21; ModuleID = 'devirt_multiple_type_test.o' 22source_filename = "devirt_multiple_type_test.cc" 23target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 24target triple = "x86_64-unknown-linux-gnu" 25 26%class.A = type { i32 (...)** } 27%class.B = type { %class.A } 28 29@_ZTV1A = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (void (%class.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !vcall_visibility !2 30@_ZTV1B = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (void (%class.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !0, !type !3, !vcall_visibility !2 31 32declare void @_ZN1A3fooEv(%class.A* nocapture %this) 33 34define hidden void @_ZN1B3fooEv(%class.B* nocapture %this) { 35entry: 36 ret void 37} 38 39; Function Attrs: nounwind readnone willreturn 40declare i1 @llvm.type.test(i8*, metadata) 41 42; Function Attrs: nounwind willreturn 43declare void @llvm.assume(i1) 44 45; Function Attrs: uwtable 46define hidden void @_Z6callerP1B(%class.B* %b) local_unnamed_addr { 47entry: 48 %0 = bitcast %class.B* %b to void (%class.B*)*** 49 %vtable = load void (%class.B*)**, void (%class.B*)*** %0, align 8, !tbaa !12, !invariant.group !15 50 %1 = bitcast void (%class.B*)** %vtable to i8* 51 %2 = tail call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1B") 52 tail call void @llvm.assume(i1 %2) 53 %3 = load void (%class.B*)*, void (%class.B*)** %vtable, align 8, !invariant.load !15 54 tail call void %3(%class.B* %b) 55 %4 = getelementptr %class.B, %class.B* %b, i64 0, i32 0 56 %5 = bitcast void (%class.B*)** %vtable to i8* 57 %6 = tail call i1 @llvm.type.test(i8* nonnull %5, metadata !"_ZTS1A") 58 tail call void @llvm.assume(i1 %6) 59 %7 = bitcast void (%class.B*)* %3 to void (%class.A*)* 60 tail call void %7(%class.A* %4) 61 ret void 62} 63 64!llvm.module.flags = !{!5, !6, !8, !9, !10} 65!llvm.ident = !{!11} 66 67!0 = !{i64 16, !"_ZTS1A"} 68!2 = !{i64 1} 69!3 = !{i64 16, !"_ZTS1B"} 70!5 = !{i32 1, !"StrictVTablePointers", i32 1} 71!6 = !{i32 3, !"StrictVTablePointersRequirement", !7} 72!7 = !{!"StrictVTablePointers", i32 1} 73!8 = !{i32 1, !"wchar_size", i32 4} 74!9 = !{i32 1, !"Virtual Function Elim", i32 0} 75!10 = !{i32 1, !"EnableSplitLTOUnit", i32 0} 76!11 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 85247c1e898f88d65154b9a437b4bd83fcad8d52)"} 77!12 = !{!13, !13, i64 0} 78!13 = !{!"vtable pointer", !14, i64 0} 79!14 = !{!"Simple C++ TBAA"} 80!15 = !{} 81