1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
;; Test that plugin option whole-program-visibility enables devirtualization.
;; Index based WPD
;; Generate unsplit module with summary for ThinLTO index-based WPD.
; RUN: opt -thinlto-bc -o %t2.o %s
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=whole-program-visibility \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t2.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
;; Hybrid WPD
;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=whole-program-visibility \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
;; Regular LTO WPD
; RUN: opt -o %t4.o %s
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=whole-program-visibility \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t4.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
;; Try everything again but without -whole-program-visibility to confirm
;; WPD fails
;; Index based WPD
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t2.o -o %t3 \
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
;; Hybrid WPD
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t.o -o %t3 \
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
;; Regular LTO WPD
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: --plugin-opt=save-temps \
; RUN: --plugin-opt=-pass-remarks=. \
; RUN: %t4.o -o %t3 \
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-grtev4-linux-gnu"
%struct.A = type { i32 (...)** }
%struct.B = type { %struct.A }
%struct.C = type { %struct.A }
%struct.D = type { i32 (...)** }
@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1, !vcall_visibility !5
@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2, !vcall_visibility !5
@_ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3, !vcall_visibility !5
; Prevent the vtables from being dead code eliminated.
@llvm.used = appending global [3 x i8*] [ i8* bitcast ( { [4 x i8*] }* @_ZTV1B to i8*), i8* bitcast ( { [4 x i8*] }* @_ZTV1C to i8*), i8* bitcast ( { [3 x i8*] }* @_ZTV1D to i8*)]
; CHECK-IR-LABEL: define dso_local i32 @_start
define i32 @_start(%struct.A* %obj, %struct.D* %obj2, i32 %a) {
entry:
%0 = bitcast %struct.A* %obj to i8***
%vtable = load i8**, i8*** %0
%1 = bitcast i8** %vtable to i8*
%p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr i8*, i8** %vtable, i32 1
%2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
%fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8
;; Check that the call was devirtualized.
; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
%call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
%3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**
%fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %3, align 8
;; We still have to call it as virtual.
; CHECK-IR: %call3 = tail call i32 %fptr22
; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
%call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32 %call)
%4 = bitcast %struct.D* %obj2 to i8***
%vtable2 = load i8**, i8*** %4
%5 = bitcast i8** %vtable2 to i8*
%p2 = call i1 @llvm.type.test(i8* %5, metadata !4)
call void @llvm.assume(i1 %p2)
%6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**
%fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*, i32)** %6, align 8
;; Check that the call was devirtualized.
; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
%call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32 %call3)
ret i32 %call4
}
; CHECK-IR-LABEL: ret i32
; CHECK-IR-LABEL: }
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)
define i32 @_ZN1B1fEi(%struct.B* %this, i32 %a) #0 {
ret i32 0;
}
define i32 @_ZN1A1nEi(%struct.A* %this, i32 %a) #0 {
ret i32 0;
}
define i32 @_ZN1C1fEi(%struct.C* %this, i32 %a) #0 {
ret i32 0;
}
define i32 @_ZN1D1mEi(%struct.D* %this, i32 %a) #0 {
ret i32 0;
}
;; Make sure we don't inline or otherwise optimize out the direct calls.
attributes #0 = { noinline optnone }
!0 = !{i64 16, !"_ZTS1A"}
!1 = !{i64 16, !"_ZTS1B"}
!2 = !{i64 16, !"_ZTS1C"}
!3 = !{i64 16, !4}
!4 = distinct !{}
!5 = !{i64 0}
|