llvm.org GIT mirror llvm / 510c1b6
Introduce GlobalSplit pass. This pass splits globals into elements using inrange annotations on getelementptr indices. Differential Revision: https://reviews.llvm.org/D22295 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@287178 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 2 years ago
9 changed file(s) with 285 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
144144 void initializeGlobalDCELegacyPassPass(PassRegistry&);
145145 void initializeGlobalMergePass(PassRegistry&);
146146 void initializeGlobalOptLegacyPassPass(PassRegistry&);
147 void initializeGlobalSplitPass(PassRegistry&);
147148 void initializeGlobalsAAWrapperPassPass(PassRegistry&);
148149 void initializeGuardWideningLegacyPassPass(PassRegistry&);
149150 void initializeIPCPPass(PassRegistry&);
224224 /// metadata.
225225 ModulePass *createWholeProgramDevirtPass();
226226
227 /// This pass splits globals into pieces for the benefit of whole-program
228 /// devirtualization and control-flow integrity.
229 ModulePass *createGlobalSplitPass();
230
227231 //===----------------------------------------------------------------------===//
228232 // SampleProfilePass - Loads sample profile data from disk and generates
229233 // IR metadata to reflect the profile.
1111 FunctionImport.cpp
1212 GlobalDCE.cpp
1313 GlobalOpt.cpp
14 GlobalSplit.cpp
1415 IPConstantPropagation.cpp
1516 IPO.cpp
1617 InferFunctionAttrs.cpp
0 //===- GlobalSplit.cpp - global variable splitter -------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass uses inrange annotations on GEP indices to split globals where
10 // beneficial. Clang currently attaches these annotations to references to
11 // virtual table globals under the Itanium ABI for the benefit of the
12 // whole-program virtual call optimization and control flow integrity passes.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/Transforms/IPO.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/IR/Constants.h"
19 #include "llvm/IR/GlobalVariable.h"
20 #include "llvm/IR/Intrinsics.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/Operator.h"
23 #include "llvm/Pass.h"
24
25 #include
26
27 using namespace llvm;
28
29 namespace {
30
31 bool splitGlobal(GlobalVariable &GV) {
32 // If the address of the global is taken outside of the module, we cannot
33 // apply this transformation.
34 if (!GV.hasLocalLinkage())
35 return false;
36
37 // We currently only know how to split ConstantStructs.
38 auto *Init = dyn_cast_or_null(GV.getInitializer());
39 if (!Init)
40 return false;
41
42 // Verify that each user of the global is an inrange getelementptr constant.
43 // From this it follows that any loads from or stores to that global must use
44 // a pointer derived from an inrange getelementptr constant, which is
45 // sufficient to allow us to apply the splitting transform.
46 for (User *U : GV.users()) {
47 if (!isa(U))
48 return false;
49
50 auto *GEP = dyn_cast(U);
51 if (!GEP || !GEP->getInRangeIndex() || *GEP->getInRangeIndex() != 1 ||
52 !isa(GEP->getOperand(1)) ||
53 !cast(GEP->getOperand(1))->isZero() ||
54 !isa(GEP->getOperand(2)))
55 return false;
56 }
57
58 SmallVector Types;
59 GV.getMetadata(LLVMContext::MD_type, Types);
60
61 const DataLayout &DL = GV.getParent()->getDataLayout();
62 const StructLayout *SL = DL.getStructLayout(Init->getType());
63
64 IntegerType *Int32Ty = Type::getInt32Ty(GV.getContext());
65
66 std::vector SplitGlobals(Init->getNumOperands());
67 for (unsigned I = 0; I != Init->getNumOperands(); ++I) {
68 // Build a global representing this split piece.
69 auto *SplitGV =
70 new GlobalVariable(*GV.getParent(), Init->getOperand(I)->getType(),
71 GV.isConstant(), GlobalValue::PrivateLinkage,
72 Init->getOperand(I), GV.getName() + "." + utostr(I));
73 SplitGlobals[I] = SplitGV;
74
75 unsigned SplitBegin = SL->getElementOffset(I);
76 unsigned SplitEnd = (I == Init->getNumOperands() - 1)
77 ? SL->getSizeInBytes()
78 : SL->getElementOffset(I + 1);
79
80 // Rebuild type metadata, adjusting by the split offset.
81 // FIXME: See if we can use DW_OP_piece to preserve debug metadata here.
82 for (MDNode *Type : Types) {
83 uint64_t ByteOffset = cast(
84 cast(Type->getOperand(0))->getValue())
85 ->getZExtValue();
86 if (ByteOffset < SplitBegin || ByteOffset >= SplitEnd)
87 continue;
88 SplitGV->addMetadata(
89 LLVMContext::MD_type,
90 *MDNode::get(GV.getContext(),
91 {ConstantAsMetadata::get(
92 ConstantInt::get(Int32Ty, ByteOffset - SplitBegin)),
93 Type->getOperand(1)}));
94 }
95 }
96
97 for (User *U : GV.users()) {
98 auto *GEP = cast(U);
99 unsigned I = cast(GEP->getOperand(2))->getZExtValue();
100 if (I >= SplitGlobals.size())
101 continue;
102
103 SmallVector Ops;
104 Ops.push_back(ConstantInt::get(Int32Ty, 0));
105 for (unsigned I = 3; I != GEP->getNumOperands(); ++I)
106 Ops.push_back(GEP->getOperand(I));
107
108 auto *NewGEP = ConstantExpr::getGetElementPtr(
109 SplitGlobals[I]->getInitializer()->getType(), SplitGlobals[I], Ops,
110 GEP->isInBounds());
111 GEP->replaceAllUsesWith(NewGEP);
112 }
113
114 // Finally, remove the original global. Any remaining uses refer to invalid
115 // elements of the global, so replace with undef.
116 if (!GV.use_empty())
117 GV.replaceAllUsesWith(UndefValue::get(GV.getType()));
118 GV.eraseFromParent();
119 return true;
120 }
121
122 bool splitGlobals(Module &M) {
123 // First, see if the module uses either of the llvm.type.test or
124 // llvm.type.checked.load intrinsics, which indicates that splitting globals
125 // may be beneficial.
126 Function *TypeTestFunc =
127 M.getFunction(Intrinsic::getName(Intrinsic::type_test));
128 Function *TypeCheckedLoadFunc =
129 M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load));
130 if ((!TypeTestFunc || TypeTestFunc->use_empty()) &&
131 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty()))
132 return false;
133
134 bool Changed = false;
135 for (auto I = M.global_begin(); I != M.global_end();) {
136 GlobalVariable &GV = *I;
137 ++I;
138 Changed |= splitGlobal(GV);
139 }
140 return Changed;
141 }
142
143 struct GlobalSplit : public ModulePass {
144 static char ID;
145 GlobalSplit() : ModulePass(ID) {
146 initializeGlobalSplitPass(*PassRegistry::getPassRegistry());
147 }
148 bool runOnModule(Module &M) {
149 if (skipModule(M))
150 return false;
151
152 return splitGlobals(M);
153 }
154 };
155
156 }
157
158 INITIALIZE_PASS(GlobalSplit, "globalsplit", "Global splitter", false, false)
159 char GlobalSplit::ID = 0;
160
161 ModulePass *llvm::createGlobalSplitPass() {
162 return new GlobalSplit;
163 }
3131 initializeForceFunctionAttrsLegacyPassPass(Registry);
3232 initializeGlobalDCELegacyPassPass(Registry);
3333 initializeGlobalOptLegacyPassPass(Registry);
34 initializeGlobalSplitPass(Registry);
3435 initializeIPCPPass(Registry);
3536 initializeAlwaysInlinerLegacyPassPass(Registry);
3637 initializeSimpleInlinerPass(Registry);
691691 PM.add(createPostOrderFunctionAttrsLegacyPass());
692692 PM.add(createReversePostOrderFunctionAttrsPass());
693693
694 // Split globals using inrange annotations on GEP indices. This can help
695 // improve the quality of generated code when virtual constant propagation or
696 // control flow integrity are enabled.
697 PM.add(createGlobalSplitPass());
698
694699 // Apply whole-program devirtualization and virtual constant propagation.
695700 PM.add(createWholeProgramDevirtPass());
696701
0 ; RUN: opt -S -globalsplit %s | FileCheck %s
1
2 target datalayout = "e-p:64:64"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 ; CHECK: @vtt = constant [3 x i8*] [i8* bitcast ([2 x i8* ()*]* @global.0 to i8*), i8* bitcast (i8* ()** getelementptr inbounds ([2 x i8* ()*], [2 x i8* ()*]* @global.0, i32 0, i32 1) to i8*), i8* bitcast ([1 x i8* ()*]* @global.1 to i8*)]
6 @vtt = constant [3 x i8*] [
7 i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 0) to i8*),
8 i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 1) to i8*),
9 i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 1, i32 0) to i8*)
10 ]
11
12 ; CHECK-NOT: @global =
13 ; CHECK: @global.0 = private constant [2 x i8* ()*] [i8* ()* @f1, i8* ()* @f2], !type [[T1:![0-9]+$]]
14 ; CHECK: @global.1 = private constant [1 x i8* ()*] [i8* ()* @f3], !type [[T2:![0-9]+$]]
15 ; CHECK-NOT: @global =
16 @global = internal constant { [2 x i8* ()*], [1 x i8* ()*] } {
17 [2 x i8* ()*] [i8* ()* @f1, i8* ()* @f2],
18 [1 x i8* ()*] [i8* ()* @f3]
19 }, !type !0, !type !1
20
21 ; CHECK: define i8* @f1()
22 define i8* @f1() {
23 ; CHECK-NEXT: ret i8* bitcast ([2 x i8* ()*]* @global.0 to i8*)
24 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 0) to i8*)
25 }
26
27 ; CHECK: define i8* @f2()
28 define i8* @f2() {
29 ; CHECK-NEXT: ret i8* bitcast (i8* ()** getelementptr inbounds ([2 x i8* ()*], [2 x i8* ()*]* @global.0, i32 0, i32 1) to i8*)
30 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 1) to i8*)
31 }
32
33 ; CHECK: define i8* @f3()
34 define i8* @f3() {
35 ; CHECK-NEXT: ret i8* bitcast (i8* ()** getelementptr inbounds ([2 x i8* ()*], [2 x i8* ()*]* @global.0, i64 1, i32 0) to i8*)
36 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 2) to i8*)
37 }
38
39 ; CHECK: define i8* @f4()
40 define i8* @f4() {
41 ; CHECK-NEXT: ret i8* bitcast ([1 x i8* ()*]* @global.1 to i8*)
42 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 1, i32 0) to i8*)
43 }
44
45 define void @foo() {
46 %p = call i1 @llvm.type.test(i8* null, metadata !"")
47 ret void
48 }
49
50 declare i1 @llvm.type.test(i8*, metadata) nounwind readnone
51
52 ; CHECK: [[T1]] = !{i32 8, !"foo"}
53 ; CHECK: [[T2]] = !{i32 0, !"bar"}
54 !0 = !{i32 8, !"foo"}
55 !1 = !{i32 16, !"bar"}
0 ; RUN: opt -S -globalsplit %s | FileCheck %s
1
2 target datalayout = "e-p:64:64"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 ; CHECK: @global =
6 @global = internal constant { [2 x i8* ()*], [1 x i8* ()*] } {
7 [2 x i8* ()*] [i8* ()* @f, i8* ()* @g],
8 [1 x i8* ()*] [i8* ()* @h]
9 }
10
11 define i8* @f() {
12 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 0) to i8*)
13 }
14
15 define i8* @g() {
16 ret i8* null
17 }
18
19 define i8* @h() {
20 ret i8* null
21 }
22
23 !0 = !{i32 16}
0 ; RUN: opt -S -globalsplit %s | FileCheck %s
1
2 target datalayout = "e-p:64:64"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 ; CHECK: @global =
6 @global = constant { [2 x i8* ()*], [1 x i8* ()*] } {
7 [2 x i8* ()*] [i8* ()* @f, i8* ()* @g],
8 [1 x i8* ()*] [i8* ()* @h]
9 }
10
11 define i8* @f() {
12 ret i8* bitcast (i8* ()** getelementptr ({ [2 x i8* ()*], [1 x i8* ()*] }, { [2 x i8* ()*], [1 x i8* ()*] }* @global, i32 0, inrange i32 0, i32 0) to i8*)
13 }
14
15 define i8* @g() {
16 ret i8* null
17 }
18
19 define i8* @h() {
20 ret i8* null
21 }
22
23 define void @foo() {
24 %p = call i1 @llvm.type.test(i8* null, metadata !"")
25 ret void
26 }
27
28 declare i1 @llvm.type.test(i8*, metadata) nounwind readnone