Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(522)

Side by Side Diff: lib/Transforms/NaCl/FlattenGlobals.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- FlattenGlobals.cpp - Flatten global variable initializers-----------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass converts initializers for global variables into a
11 // flattened normal form which removes nested struct types and
12 // simplifies ConstantExprs.
13 //
14 // In this normal form, an initializer is either a SimpleElement or a
15 // CompoundElement.
16 //
17 // A SimpleElement is one of the following:
18 //
19 // 1) An i8 array literal or zeroinitializer:
20 //
21 // [SIZE x i8] c"DATA"
22 // [SIZE x i8] zeroinitializer
23 //
24 // 2) A reference to a GlobalValue (a function or global variable)
25 // with an optional 32-bit byte offset added to it (the addend):
26 //
27 // ptrtoint (TYPE* @GLOBAL to i32)
28 // add (i32 ptrtoint (TYPE* @GLOBAL to i32), i32 ADDEND)
29 //
30 // We use ptrtoint+add rather than bitcast+getelementptr because
31 // the constructor for getelementptr ConstantExprs performs
32 // constant folding which introduces more complex getelementptrs,
33 // and it is hard to check that they follow a normal form.
34 //
35 // For completeness, the pass also allows a BlockAddress as well as
36 // a GlobalValue here, although BlockAddresses are currently not
37 // allowed in the PNaCl ABI, so this should not be considered part
38 // of the normal form.
39 //
40 // A CompoundElement is a unnamed, packed struct containing only
41 // SimpleElements.
42 //
43 // Limitations:
44 //
45 // LLVM IR allows ConstantExprs that calculate the difference between
46 // two globals' addresses. FlattenGlobals rejects these because Clang
47 // does not generate these and because ELF does not support such
48 // relocations in general.
49 //
50 //===----------------------------------------------------------------------===//
51
52 #include "llvm/ADT/DenseMap.h"
53 #include "llvm/ADT/SmallVector.h"
54 #include "llvm/ADT/STLExtras.h"
55 #include "llvm/IR/Constants.h"
56 #include "llvm/IR/DataLayout.h"
57 #include "llvm/IR/DerivedTypes.h"
58 #include "llvm/IR/Instructions.h"
59 #include "llvm/IR/Module.h"
60 #include "llvm/Pass.h"
61 #include "llvm/Support/raw_ostream.h"
62 #include "llvm/Transforms/NaCl.h"
63
64 using namespace llvm;
65
66 namespace {
67
68 // Defines a (non-constant) handle that records a use of a
69 // constant. Used to make sure a relocation, within flattened global
70 // variable initializers, does not get destroyed when method
71 // removeDeadConstantUsers gets called. For simplicity, rather than
72 // defining a new (non-constant) construct, we use a return
73 // instruction as the handle.
74 typedef ReturnInst RelocUserType;
75
76 // Define map from a relocation, appearing in the flattened global variable
77 // initializers, to it's corresponding use handle.
78 typedef DenseMap<Constant*, RelocUserType*> RelocMapType;
79
80 // Define the list to hold the list of global variables being flattened.
81 struct FlattenedGlobal;
82 typedef std::vector<FlattenedGlobal*> FlattenedGlobalsVectorType;
83
84 // Returns the corresponding relocation, for the given user handle.
85 Constant *getRelocUseConstant(RelocUserType *RelocUser) {
86 return cast<Constant>(RelocUser->getReturnValue());
87 }
88
89 // The state associated with flattening globals of a module.
90 struct FlattenGlobalsState {
91 /// The module being flattened.
92 Module &M;
93 /// The data layout to be used.
94 DataLayout DL;
95 /// The relocations (within the original global variable initializers)
96 /// that must be kept.
97 RelocMapType RelocMap;
98 /// The list of global variables that are being flattened.
99 FlattenedGlobalsVectorType FlattenedGlobalsVector;
100 /// True if the module was modified during the "flatten globals" pass.
101 bool Modified;
102 /// The type model of a byte.
103 Type *ByteType;
104 /// The type model of the integer pointer type.
105 Type *IntPtrType;
106 /// The size of the pointer type.
107 unsigned PtrSize;
108
109 explicit FlattenGlobalsState(Module &M)
110 : M(M), DL(&M), RelocMap(),
111 Modified(false),
112 ByteType(Type::getInt8Ty(M.getContext())),
113 IntPtrType(DL.getIntPtrType(M.getContext())),
114 PtrSize(DL.getPointerSize())
115 {}
116
117 ~FlattenGlobalsState() {
118 // Remove added user handles.
119 for (RelocMapType::iterator
120 I = RelocMap.begin(), E = RelocMap.end(); I != E; ++I) {
121 delete I->second;
122 }
123 // Remove flatteners for global varaibles.
124 DeleteContainerPointers(FlattenedGlobalsVector);
125 }
126
127 /// Collect Global variables whose initializers should be
128 /// flattened. Creates corresponding flattened initializers (if
129 /// applicable), and creates uninitialized replacement global
130 /// variables.
131 void flattenGlobalsWithInitializers();
132
133 /// Remove initializers from original global variables, and
134 /// then remove the portions of the initializers that are
135 /// no longer used.
136 void removeDeadInitializerConstants();
137
138 // Replace the original global variables with their flattened
139 // global variable counterparts.
140 void replaceGlobalsWithFlattenedGlobals();
141
142 // Builds and installs initializers for flattened global
143 // variables, based on the flattened initializers of the
144 // corresponding original global variables.
145 void installFlattenedGlobalInitializers();
146
147 // Returns the user handle associated with the reloc, so that it
148 // won't be deleted during the flattening process.
149 RelocUserType *getRelocUserHandle(Constant *Reloc) {
150 RelocUserType *RelocUser = RelocMap[Reloc];
151 if (RelocUser == NULL) {
152 RelocUser = ReturnInst::Create(M.getContext(), Reloc);
153 RelocMap[Reloc] = RelocUser;
154 }
155 return RelocUser;
156 }
157 };
158
159 // A FlattenedConstant represents a global variable initializer that
160 // has been flattened and may be converted into the normal form.
161 class FlattenedConstant {
162 FlattenGlobalsState &State;
163
164 // A flattened global variable initializer is represented as:
165 // 1) an array of bytes;
166 unsigned BufSize;
167 uint8_t *Buf;
168 uint8_t *BufEnd;
169
170 // 2) an array of relocations.
171 class Reloc {
172 private:
173 unsigned RelOffset; // Offset at which the relocation is to be applied.
174 RelocUserType *RelocUser;
175 public:
176
177 unsigned getRelOffset() const { return RelOffset; }
178 Constant *getRelocUse() const { return getRelocUseConstant(RelocUser); }
179 Reloc(FlattenGlobalsState &State, unsigned RelOffset, Constant *NewVal)
180 : RelOffset(RelOffset), RelocUser(State.getRelocUserHandle(NewVal)) {}
181
182 explicit Reloc(const Reloc &R)
183 : RelOffset(R.RelOffset), RelocUser(R.RelocUser) {}
184
185 void operator=(const Reloc &R) {
186 RelOffset = R.RelOffset;
187 RelocUser = R.RelocUser;
188 }
189 };
190 typedef SmallVector<Reloc, 10> RelocArray;
191 RelocArray Relocs;
192
193 const DataLayout &getDataLayout() const { return State.DL; }
194
195 Module &getModule() const { return State.M; }
196
197 Type *getIntPtrType() const { return State.IntPtrType; }
198
199 Type *getByteType() const { return State.ByteType; }
200
201 unsigned getPtrSize() const { return State.PtrSize; }
202
203 void putAtDest(Constant *Value, uint8_t *Dest);
204
205 Constant *dataSlice(unsigned StartPos, unsigned EndPos) const {
206 return ConstantDataArray::get(
207 getModule().getContext(),
208 ArrayRef<uint8_t>(Buf + StartPos, Buf + EndPos));
209 }
210
211 Type *dataSliceType(unsigned StartPos, unsigned EndPos) const {
212 return ArrayType::get(getByteType(), EndPos - StartPos);
213 }
214
215 public:
216 FlattenedConstant(FlattenGlobalsState &State, Constant *Value):
217 State(State),
218 BufSize(getDataLayout().getTypeAllocSize(Value->getType())),
219 Buf(new uint8_t[BufSize]),
220 BufEnd(Buf + BufSize) {
221 memset(Buf, 0, BufSize);
222 putAtDest(Value, Buf);
223 }
224
225 ~FlattenedConstant() {
226 delete[] Buf;
227 }
228
229 // Returns the corresponding flattened initializer.
230 Constant *getAsNormalFormConstant() const;
231
232 // Returns the type of the corresponding flattened initializer;
233 Type *getAsNormalFormType() const;
234
235 };
236
237 // Structure used to flatten a global variable.
238 struct FlattenedGlobal {
239 // The state of the flatten globals pass.
240 FlattenGlobalsState &State;
241 // The global variable to flatten.
242 GlobalVariable *Global;
243 // The replacement global variable, if known.
244 GlobalVariable *NewGlobal;
245 // True if Global has an initializer.
246 bool HasInitializer;
247 // The flattened initializer, if the initializer would not just be
248 // filled with zeroes.
249 FlattenedConstant *FlatConst;
250 // The type of GlobalType, when used in an initializer.
251 Type *GlobalType;
252 // The size of the initializer.
253 uint64_t Size;
254 public:
255 FlattenedGlobal(FlattenGlobalsState &State, GlobalVariable *Global)
256 : State(State),
257 Global(Global),
258 NewGlobal(NULL),
259 HasInitializer(Global->hasInitializer()),
260 FlatConst(NULL),
261 GlobalType(Global->getType()->getPointerElementType()),
262 Size(GlobalType->isSized()
263 ? getDataLayout().getTypeAllocSize(GlobalType) : 0) {
264 Type *NewType = NULL;
265 if (HasInitializer) {
266 if (Global->getInitializer()->isNullValue()) {
267 // Special case of NullValue. As an optimization, for large
268 // BSS variables, avoid allocating a buffer that would only be filled
269 // with zeros.
270 NewType = ArrayType::get(getByteType(), Size);
271 } else {
272 FlatConst = new FlattenedConstant(State, Global->getInitializer());
273 NewType = FlatConst->getAsNormalFormType();
274 }
275 } else {
276 NewType = ArrayType::get(getByteType(), Size);
277 }
278 NewGlobal = new GlobalVariable(getModule(), NewType,
279 Global->isConstant(),
280 Global->getLinkage(),
281 NULL, "", Global,
282 Global->getThreadLocalMode());
283 NewGlobal->copyAttributesFrom(Global);
284 if (NewGlobal->getAlignment() == 0 && GlobalType->isSized())
285 NewGlobal->setAlignment(getDataLayout().
286 getPrefTypeAlignment(GlobalType));
287 NewGlobal->setExternallyInitialized(Global->isExternallyInitialized());
288 NewGlobal->takeName(Global);
289 }
290
291 ~FlattenedGlobal() {
292 delete FlatConst;
293 }
294
295 const DataLayout &getDataLayout() const { return State.DL; }
296
297 Module &getModule() const { return State.M; }
298
299 Type *getByteType() const { return State.ByteType; }
300
301 // Removes the original initializer from the global variable to be
302 // flattened, if applicable.
303 void removeOriginalInitializer() {
304 if (HasInitializer) Global->setInitializer(NULL);
305 }
306
307 // Replaces the original global variable with the corresponding
308 // flattened global variable.
309 void replaceGlobalWithFlattenedGlobal() {
310 Global->replaceAllUsesWith(
311 ConstantExpr::getBitCast(NewGlobal, Global->getType()));
312 Global->eraseFromParent();
313 }
314
315 // Installs flattened initializers to the corresponding flattened
316 // global variable.
317 void installFlattenedInitializer() {
318 if (HasInitializer) {
319 Constant *NewInit = NULL;
320 if (FlatConst == NULL) {
321 // Special case of NullValue.
322 NewInit = ConstantAggregateZero::get(ArrayType::get(getByteType(),
323 Size));
324 } else {
325 NewInit = FlatConst->getAsNormalFormConstant();
326 }
327 NewGlobal->setInitializer(NewInit);
328 }
329 }
330 };
331
332 class FlattenGlobals : public ModulePass {
333 public:
334 static char ID; // Pass identification, replacement for typeid
335 FlattenGlobals() : ModulePass(ID) {
336 initializeFlattenGlobalsPass(*PassRegistry::getPassRegistry());
337 }
338
339 virtual bool runOnModule(Module &M);
340 };
341 }
342
343 static void ExpandConstant(const DataLayout *DL, Constant *Val,
344 Constant **ResultGlobal, uint64_t *ResultOffset) {
345 if (isa<GlobalValue>(Val) || isa<BlockAddress>(Val)) {
346 *ResultGlobal = Val;
347 *ResultOffset = 0;
348 } else if (isa<ConstantPointerNull>(Val)) {
349 *ResultGlobal = NULL;
350 *ResultOffset = 0;
351 } else if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
352 *ResultGlobal = NULL;
353 *ResultOffset = CI->getZExtValue();
354 } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Val)) {
355 ExpandConstant(DL, CE->getOperand(0), ResultGlobal, ResultOffset);
356 if (CE->getOpcode() == Instruction::GetElementPtr) {
357 SmallVector<Value *, 8> Indexes(CE->op_begin() + 1, CE->op_end());
358 *ResultOffset += DL->getIndexedOffset(CE->getOperand(0)->getType(),
359 Indexes);
360 } else if (CE->getOpcode() == Instruction::BitCast ||
361 CE->getOpcode() == Instruction::IntToPtr) {
362 // Nothing more to do.
363 } else if (CE->getOpcode() == Instruction::PtrToInt) {
364 if (Val->getType()->getIntegerBitWidth() < DL->getPointerSizeInBits()) {
365 errs() << "Not handled: " << *CE << "\n";
366 report_fatal_error("FlattenGlobals: a ptrtoint that truncates "
367 "a pointer is not allowed");
368 }
369 } else {
370 errs() << "Not handled: " << *CE << "\n";
371 report_fatal_error(
372 std::string("FlattenGlobals: ConstantExpr opcode not handled: ")
373 + CE->getOpcodeName());
374 }
375 } else {
376 errs() << "Not handled: " << *Val << "\n";
377 report_fatal_error("FlattenGlobals: Constant type not handled for reloc");
378 }
379 }
380
381 void FlattenedConstant::putAtDest(Constant *Val, uint8_t *Dest) {
382 uint64_t ValSize = getDataLayout().getTypeAllocSize(Val->getType());
383 assert(Dest + ValSize <= BufEnd);
384 if (isa<ConstantAggregateZero>(Val) ||
385 isa<UndefValue>(Val) ||
386 isa<ConstantPointerNull>(Val)) {
387 // The buffer is already zero-initialized.
388 } else if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
389 memcpy(Dest, CI->getValue().getRawData(), ValSize);
390 } else if (ConstantFP *CF = dyn_cast<ConstantFP>(Val)) {
391 APInt Data = CF->getValueAPF().bitcastToAPInt();
392 assert((Data.getBitWidth() + 7) / 8 == ValSize);
393 assert(Data.getBitWidth() % 8 == 0);
394 memcpy(Dest, Data.getRawData(), ValSize);
395 } else if (ConstantDataSequential *CD =
396 dyn_cast<ConstantDataSequential>(Val)) {
397 // Note that getRawDataValues() assumes the host endianness is the same.
398 StringRef Data = CD->getRawDataValues();
399 assert(Data.size() == ValSize);
400 memcpy(Dest, Data.data(), Data.size());
401 } else if (isa<ConstantArray>(Val) || isa<ConstantDataVector>(Val) ||
402 isa<ConstantVector>(Val)) {
403 uint64_t ElementSize = getDataLayout().getTypeAllocSize(
404 Val->getType()->getSequentialElementType());
405 for (unsigned I = 0; I < Val->getNumOperands(); ++I) {
406 putAtDest(cast<Constant>(Val->getOperand(I)), Dest + ElementSize * I);
407 }
408 } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Val)) {
409 const StructLayout *Layout = getDataLayout().getStructLayout(CS->getType());
410 for (unsigned I = 0; I < CS->getNumOperands(); ++I) {
411 putAtDest(CS->getOperand(I), Dest + Layout->getElementOffset(I));
412 }
413 } else {
414 Constant *GV;
415 uint64_t Offset;
416 ExpandConstant(&getDataLayout(), Val, &GV, &Offset);
417 if (GV) {
418 Constant *NewVal = ConstantExpr::getPtrToInt(GV, getIntPtrType());
419 if (Offset) {
420 // For simplicity, require addends to be 32-bit.
421 if ((int64_t) Offset != (int32_t) (uint32_t) Offset) {
422 errs() << "Not handled: " << *Val << "\n";
423 report_fatal_error(
424 "FlattenGlobals: Offset does not fit into 32 bits");
425 }
426 NewVal = ConstantExpr::getAdd(
427 NewVal, ConstantInt::get(getIntPtrType(), Offset,
428 /* isSigned= */ true));
429 }
430 Reloc NewRel(State, Dest - Buf, NewVal);
431 Relocs.push_back(NewRel);
432 } else {
433 memcpy(Dest, &Offset, ValSize);
434 }
435 }
436 }
437
438 Constant *FlattenedConstant::getAsNormalFormConstant() const {
439 // Return a single SimpleElement.
440 if (Relocs.size() == 0)
441 return dataSlice(0, BufSize);
442 if (Relocs.size() == 1 && BufSize == getPtrSize()) {
443 assert(Relocs[0].getRelOffset() == 0);
444 return Relocs[0].getRelocUse();
445 }
446
447 // Return a CompoundElement.
448 SmallVector<Constant *, 10> Elements;
449 unsigned PrevPos = 0;
450 for (RelocArray::const_iterator Rel = Relocs.begin(), E = Relocs.end();
451 Rel != E; ++Rel) {
452 if (Rel->getRelOffset() > PrevPos)
453 Elements.push_back(dataSlice(PrevPos, Rel->getRelOffset()));
454 Elements.push_back(Rel->getRelocUse());
455 PrevPos = Rel->getRelOffset() + getPtrSize();
456 }
457 if (PrevPos < BufSize)
458 Elements.push_back(dataSlice(PrevPos, BufSize));
459 return ConstantStruct::getAnon(getModule().getContext(), Elements, true);
460 }
461
462 Type *FlattenedConstant::getAsNormalFormType() const {
463 // Return a single element type.
464 if (Relocs.size() == 0)
465 return dataSliceType(0, BufSize);
466 if (Relocs.size() == 1 && BufSize == getPtrSize()) {
467 assert(Relocs[0].getRelOffset() == 0);
468 return Relocs[0].getRelocUse()->getType();
469 }
470
471 // Return a compound type.
472 SmallVector<Type *, 10> Elements;
473 unsigned PrevPos = 0;
474 for (RelocArray::const_iterator Rel = Relocs.begin(), E = Relocs.end();
475 Rel != E; ++Rel) {
476 if (Rel->getRelOffset() > PrevPos)
477 Elements.push_back(dataSliceType(PrevPos, Rel->getRelOffset()));
478 Elements.push_back(Rel->getRelocUse()->getType());
479 PrevPos = Rel->getRelOffset() + getPtrSize();
480 }
481 if (PrevPos < BufSize)
482 Elements.push_back(dataSliceType(PrevPos, BufSize));
483 return StructType::get(getModule().getContext(), Elements, true);
484 }
485
486 char FlattenGlobals::ID = 0;
487 INITIALIZE_PASS(FlattenGlobals, "flatten-globals",
488 "Flatten global variable initializers into byte arrays",
489 false, false)
490
491 void FlattenGlobalsState::flattenGlobalsWithInitializers() {
492 for (Module::global_iterator I = M.global_begin(), E = M.global_end();
493 I != E;) {
494 GlobalVariable *Global = I++;
495 // Variables with "appending" linkage must always be arrays and so
496 // cannot be normalized, so leave them alone.
497 if (Global->hasAppendingLinkage())
498 continue;
499 Modified = true;
500 FlattenedGlobalsVector.push_back(new FlattenedGlobal(*this, Global));
501 }
502 }
503
504 void FlattenGlobalsState::removeDeadInitializerConstants() {
505 // Detach original initializers.
506 for (FlattenedGlobalsVectorType::iterator
507 I = FlattenedGlobalsVector.begin(), E = FlattenedGlobalsVector.end();
508 I != E; ++I) {
509 (*I)->removeOriginalInitializer();
510 }
511 // Do cleanup of old initializers.
512 for (RelocMapType::iterator I = RelocMap.begin(), E = RelocMap.end();
513 I != E; ++I) {
514 getRelocUseConstant(I->second)->removeDeadConstantUsers();
515 }
516
517 }
518
519 void FlattenGlobalsState::replaceGlobalsWithFlattenedGlobals() {
520 for (FlattenedGlobalsVectorType::iterator
521 I = FlattenedGlobalsVector.begin(), E = FlattenedGlobalsVector.end();
522 I != E; ++I) {
523 (*I)->replaceGlobalWithFlattenedGlobal();
524 }
525 }
526
527 void FlattenGlobalsState::installFlattenedGlobalInitializers() {
528 for (FlattenedGlobalsVectorType::iterator
529 I = FlattenedGlobalsVector.begin(), E = FlattenedGlobalsVector.end();
530 I != E; ++I) {
531 (*I)->installFlattenedInitializer();
532 }
533 }
534
535 bool FlattenGlobals::runOnModule(Module &M) {
536 FlattenGlobalsState State(M);
537 State.flattenGlobalsWithInitializers();
538 State.removeDeadInitializerConstants();
539 State.replaceGlobalsWithFlattenedGlobals();
540 State.installFlattenedGlobalInitializers();
541 return State.Modified;
542 }
543
544 ModulePass *llvm::createFlattenGlobalsPass() {
545 return new FlattenGlobals();
546 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/FixVectorLoadStoreAlignment.cpp ('k') | lib/Transforms/NaCl/GlobalCleanup.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698