1; RUN: opt < %s -passes=globaldce -S | FileCheck %s 2 3target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 5; struct A { 6; A(); 7; virtual int foo(); 8; }; 9; 10; struct B : A { 11; B(); 12; virtual int foo(); 13; }; 14; 15; A::A() {} 16; B::B() {} 17; int A::foo() { return 42; } 18; int B::foo() { return 1337; } 19; 20; extern "C" int test(B *p) { return p->foo(); } 21 22; The virtual call in test can only be dispatched to B::foo (or a more-derived 23; class, if there was one), so A::foo can be removed. 24 25%struct.A = type { ptr } 26%struct.B = type { %struct.A } 27 28; CHECK: @_ZTV1A = internal unnamed_addr constant { [3 x ptr] } zeroinitializer 29@_ZTV1A = internal unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZN1A3fooEv] }, align 8, !type !0, !type !1, !vcall_visibility !2 30 31; CHECK: @_ZTV1B = internal unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZN1B3fooEv] } 32@_ZTV1B = internal unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZN1B3fooEv] }, align 8, !type !0, !type !1, !type !3, !type !4, !vcall_visibility !2 33 34; CHECK-NOT: define internal i32 @_ZN1A3fooEv( 35define internal i32 @_ZN1A3fooEv(ptr nocapture readnone %this) { 36entry: 37 ret i32 42 38} 39 40; CHECK: define internal i32 @_ZN1B3fooEv( 41define internal i32 @_ZN1B3fooEv(ptr nocapture readnone %this) { 42entry: 43 ret i32 1337 44} 45 46define hidden void @_ZN1AC2Ev(ptr nocapture %this) { 47entry: 48 store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV1A, i64 0, i32 0, i64 2), ptr %this, align 8 49 ret void 50} 51 52define hidden void @_ZN1BC2Ev(ptr nocapture %this) { 53entry: 54 store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV1B, i64 0, i32 0, i64 2), ptr %this, align 8 55 ret void 56} 57 58define hidden i32 @test(ptr %p) { 59entry: 60 %vtable1 = load ptr, ptr %p, align 8 61 %0 = tail call { ptr, i1 } @llvm.type.checked.load(ptr %vtable1, i32 0, metadata !"_ZTS1B"), !nosanitize !10 62 %1 = extractvalue { ptr, i1 } %0, 0, !nosanitize !10 63 %call = tail call i32 %1(ptr %p) 64 ret i32 %call 65} 66 67declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata) #2 68 69!llvm.module.flags = !{!5} 70 71!0 = !{i64 16, !"_ZTS1A"} 72!1 = !{i64 16, !"_ZTSM1AFivE.virtual"} 73!2 = !{i64 2} 74!3 = !{i64 16, !"_ZTS1B"} 75!4 = !{i64 16, !"_ZTSM1BFivE.virtual"} 76!5 = !{i32 1, !"Virtual Function Elim", i32 1} 77!10 = !{} 78