OLD | NEW |
---|---|
(Empty) | |
1 //===- ConstantInsertExtractElementIndex.cpp - Insert/Extract element -----===// | |
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 // Transform all InsertElement and ExtractElement with non-constant or | |
11 // out-of-bounds indices into either in-bounds constant accesses or | |
12 // stack accesses. This moves all undefined behavior to the stack, | |
13 // making InsertElement and ExtractElement well-defined. | |
14 // | |
15 //===----------------------------------------------------------------------===// | |
16 | |
17 #include "llvm/IR/DataLayout.h" | |
18 #include "llvm/IR/IRBuilder.h" | |
19 #include "llvm/IR/Instruction.h" | |
20 #include "llvm/IR/Instructions.h" | |
21 #include "llvm/IR/Module.h" | |
22 #include "llvm/Pass.h" | |
23 #include "llvm/Transforms/NaCl.h" | |
24 | |
25 #include <algorithm> | |
26 | |
27 using namespace llvm; | |
28 | |
29 namespace { | |
30 class ConstantInsertExtractElementIndex : public BasicBlockPass { | |
31 public: | |
32 static char ID; // Pass identification, replacement for typeid | |
33 ConstantInsertExtractElementIndex() : BasicBlockPass(ID), M(0), DL(0) { | |
34 initializeConstantInsertExtractElementIndexPass( | |
35 *PassRegistry::getPassRegistry()); | |
36 } | |
37 virtual void getAnalysisUsage(AnalysisUsage &AU) const { | |
38 AU.addRequired<DataLayout>(); | |
39 BasicBlockPass::getAnalysisUsage(AU); | |
40 } | |
41 virtual bool doInitialization(Module &Mod) { | |
42 M = &Mod; | |
43 return false; // Unchanged. | |
44 } | |
45 virtual bool runOnBasicBlock(BasicBlock &BB); | |
46 | |
47 private: | |
48 typedef SmallVector<Instruction *, 8> Instructions; | |
49 const Module *M; | |
50 const DataLayout *DL; | |
51 | |
52 void findNonConstantInsertExtractElements( | |
53 const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, | |
54 Instructions &NonConstantVectorIndices) const; | |
55 void fixOutOfRangeConstantIndices(BasicBlock &BB, | |
56 const Instructions &Instrs) const; | |
57 void fixNonConstantVectorIndices(BasicBlock &BB, | |
58 const Instructions &Instrs) const; | |
59 }; | |
60 | |
61 /// Number of elements in a vector instruction. | |
62 unsigned vectorNumElements(const Instruction *I) { | |
63 return cast<VectorType>(I->getOperand(0)->getType())->getNumElements(); | |
64 } | |
65 | |
66 /// Get the index of an InsertElement or ExtractElement instruction, or null. | |
67 Value *getInsertExtractElementIdx(const Instruction *I) { | |
68 switch (I->getOpcode()) { | |
69 default: return NULL; | |
70 case Instruction::InsertElement: return I->getOperand(2); | |
71 case Instruction::ExtractElement: return I->getOperand(1); | |
72 } | |
73 } | |
74 | |
75 /// Set the index of an InsertElement or ExtractElement instruction. | |
76 void setInsertExtractElementIdx(Instruction *I, Value *NewIdx) { | |
77 switch (I->getOpcode()) { | |
78 default: | |
79 llvm_unreachable( | |
80 "expected instruction to be InsertElement or ExtractElement"); | |
81 case Instruction::InsertElement: I->setOperand(2, NewIdx); break; | |
82 case Instruction::ExtractElement: I->setOperand(1, NewIdx); break; | |
83 } | |
84 } | |
85 } // anonymous namespace | |
86 | |
87 char ConstantInsertExtractElementIndex::ID = 0; | |
88 INITIALIZE_PASS( | |
89 ConstantInsertExtractElementIndex, "constant-insert-extract-element-index", | |
90 "Force insert and extract vector element to always be in bounds", false, | |
91 false) | |
92 | |
93 void ConstantInsertExtractElementIndex::findNonConstantInsertExtractElements( | |
94 const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, | |
95 Instructions &NonConstantVectorIndices) const { | |
96 for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; | |
97 ++BBI) { | |
98 const Instruction *I = &*BBI; | |
99 if (Value *Idx = getInsertExtractElementIdx(I)) { | |
100 if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) { | |
101 if (!CI->getValue().ult(vectorNumElements(I))) | |
102 OutOfRangeConstantIndices.push_back(const_cast<Instruction *>(I)); | |
103 } else | |
104 NonConstantVectorIndices.push_back(const_cast<Instruction *>(I)); | |
105 } | |
106 } | |
107 } | |
108 | |
109 void ConstantInsertExtractElementIndex::fixOutOfRangeConstantIndices( | |
110 BasicBlock &BB, const Instructions &Instrs) const { | |
111 for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); | |
112 IB != IE; ++IB) { | |
113 Instruction *I = *IB; | |
114 const APInt &Idx = cast<ConstantInt>(getInsertExtractElementIdx(I))->getValu e(); | |
Derek Schuff
2014/04/15 20:30:43
80 col
JF
2014/04/15 20:43:26
Done.
| |
115 APInt NumElements = APInt(Idx.getBitWidth(), vectorNumElements(I)); | |
116 APInt NewIdx = Idx.urem(NumElements); | |
117 setInsertExtractElementIdx(I, ConstantInt::get(M->getContext(), NewIdx)); | |
118 } | |
119 } | |
120 | |
121 void ConstantInsertExtractElementIndex::fixNonConstantVectorIndices( | |
122 BasicBlock &BB, const Instructions &Instrs) const { | |
123 for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); | |
124 IB != IE; ++IB) { | |
125 Instruction *I = *IB; | |
126 Value *Vec = I->getOperand(0); | |
127 Value *Idx = getInsertExtractElementIdx(I); | |
128 VectorType *VecTy = cast<VectorType>(Vec->getType()); | |
129 Type *ElemTy = VecTy->getElementType(); | |
130 unsigned ElemAlign = DL->getPrefTypeAlignment(ElemTy); | |
131 unsigned VecAlign = std::max(ElemAlign, DL->getPrefTypeAlignment(VecTy)); | |
132 | |
133 IRBuilder<> IRB(I); | |
134 AllocaInst *Alloca = IRB.CreateAlloca( | |
135 ElemTy, ConstantInt::get(Type::getInt32Ty(M->getContext()), | |
136 vectorNumElements(I))); | |
137 Alloca->setAlignment(VecAlign); | |
138 Value *AllocaAsVec = IRB.CreateBitCast(Alloca, VecTy->getPointerTo()); | |
139 IRB.CreateAlignedStore(Vec, AllocaAsVec, Alloca->getAlignment()); | |
140 Value *GEP = IRB.CreateGEP(Alloca, Idx); | |
141 | |
142 Value *Res; | |
143 switch (I->getOpcode()) { | |
144 default: | |
145 llvm_unreachable("expected InsertElement or ExtractElement"); | |
146 case Instruction::InsertElement: | |
147 IRB.CreateAlignedStore(I->getOperand(1), GEP, ElemAlign); | |
148 Res = IRB.CreateAlignedLoad(AllocaAsVec, Alloca->getAlignment()); | |
149 break; | |
150 case Instruction::ExtractElement: | |
151 Res = IRB.CreateAlignedLoad(GEP, ElemAlign); | |
152 break; | |
153 } | |
154 | |
155 I->replaceAllUsesWith(Res); | |
156 I->eraseFromParent(); | |
157 } | |
158 } | |
159 | |
160 bool ConstantInsertExtractElementIndex::runOnBasicBlock(BasicBlock &BB) { | |
161 bool Changed = false; | |
162 if (!DL) | |
163 DL = &getAnalysis<DataLayout>(); | |
164 Instructions OutOfRangeConstantIndices; | |
165 Instructions NonConstantVectorIndices; | |
166 | |
167 findNonConstantInsertExtractElements(BB, OutOfRangeConstantIndices, | |
168 NonConstantVectorIndices); | |
169 if (!OutOfRangeConstantIndices.empty()) { | |
170 Changed = true; | |
171 fixOutOfRangeConstantIndices(BB, OutOfRangeConstantIndices); | |
172 } | |
173 if (!NonConstantVectorIndices.empty()) { | |
174 Changed = true; | |
175 fixNonConstantVectorIndices(BB, NonConstantVectorIndices); | |
176 } | |
177 return Changed; | |
178 } | |
179 | |
180 BasicBlockPass *llvm::createConstantInsertExtractElementIndexPass() { | |
181 return new ConstantInsertExtractElementIndex(); | |
182 } | |
OLD | NEW |