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

Side by Side Diff: lib/Transforms/NaCl/FixVectorLoadStoreAlignment.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
« no previous file with comments | « lib/Transforms/NaCl/ExpandVarArgs.cpp ('k') | lib/Transforms/NaCl/FlattenGlobals.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- FixVectorLoadStoreAlignment.cpp - Vector load/store alignment ------===//
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 // Fix vector load/store alignment by:
11 // - Leaving as-is if the alignment is equal to the vector's element width.
12 // - Reducing the alignment to vector's element width if it's greater and the
13 // current alignment is a factor of the element alignment.
14 // - Scalarizing if the alignment is smaller than the element-wise alignment.
15 //
16 // Volatile vector load/store are handled the same, and can therefore be broken
17 // up as allowed by C/C++.
18 //
19 // TODO(jfb) Atomic accesses cause errors at compile-time. This could be
20 // implemented as a call to the C++ runtime, since 128-bit atomics
21 // aren't usually lock-free.
22 //
23 //===----------------------------------------------------------------------===//
24
25 #include "llvm/IR/DataLayout.h"
26 #include "llvm/IR/IRBuilder.h"
27 #include "llvm/IR/Instruction.h"
28 #include "llvm/IR/Instructions.h"
29 #include "llvm/IR/Module.h"
30 #include "llvm/Pass.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/MathExtras.h"
33 #include "llvm/Transforms/NaCl.h"
34
35 using namespace llvm;
36
37 namespace {
38 class FixVectorLoadStoreAlignment : public BasicBlockPass {
39 public:
40 static char ID; // Pass identification, replacement for typeid
41 FixVectorLoadStoreAlignment() : BasicBlockPass(ID), M(0), DL(0) {
42 initializeFixVectorLoadStoreAlignmentPass(*PassRegistry::getPassRegistry());
43 }
44 void getAnalysisUsage(AnalysisUsage &AU) const override {
45 AU.addRequired<DataLayoutPass>();
46 BasicBlockPass::getAnalysisUsage(AU);
47 }
48 using BasicBlockPass::doInitialization;
49 bool doInitialization(Module &Mod) override {
50 M = &Mod;
51 return false; // Unchanged.
52 }
53 bool runOnBasicBlock(BasicBlock &BB) override;
54
55 private:
56 typedef SmallVector<Instruction *, 8> Instructions;
57 const Module *M;
58 const DataLayout *DL;
59
60 /// Some sub-classes of Instruction have a non-virtual function
61 /// indicating which operand is the pointer operand. This template
62 /// function returns the pointer operand's type, and requires that
63 /// InstTy have a getPointerOperand function.
64 template <typename InstTy>
65 static PointerType *pointerOperandType(const InstTy *I) {
66 return cast<PointerType>(I->getPointerOperand()->getType());
67 }
68
69 /// Similar to pointerOperandType, this template function checks
70 /// whether the pointer operand is a pointer to a vector type.
71 template <typename InstTy>
72 static bool pointerOperandIsVectorPointer(const Instruction *I) {
73 return pointerOperandType(cast<InstTy>(I))->getElementType()->isVectorTy();
74 }
75
76 /// Returns true if one of the Instruction's operands is a pointer to
77 /// a vector type. This is more general than the above and assumes we
78 /// don't know which Instruction type is provided.
79 static bool hasVectorPointerOperand(const Instruction *I) {
80 for (User::const_op_iterator IB = I->op_begin(), IE = I->op_end(); IB != IE;
81 ++IB)
82 if (PointerType *PtrTy = dyn_cast<PointerType>((*IB)->getType()))
83 if (isa<VectorType>(PtrTy->getElementType()))
84 return true;
85 return false;
86 }
87
88 /// Vectors are expected to be element-aligned. If they are, leave as-is; if
89 /// the alignment is too much then narrow the alignment (when possible);
90 /// otherwise return false.
91 template <typename InstTy>
92 static bool tryFixVectorAlignment(const DataLayout *DL, Instruction *I) {
93 InstTy *LoadStore = cast<InstTy>(I);
94 VectorType *VecTy =
95 cast<VectorType>(pointerOperandType(LoadStore)->getElementType());
96 Type *ElemTy = VecTy->getElementType();
97 uint64_t ElemBitSize = DL->getTypeSizeInBits(ElemTy);
98 uint64_t ElemByteSize = ElemBitSize / CHAR_BIT;
99 uint64_t CurrentByteAlign = LoadStore->getAlignment();
100 bool isABIAligned = CurrentByteAlign == 0;
101 uint64_t VecABIByteAlign = DL->getABITypeAlignment(VecTy);
102 CurrentByteAlign = isABIAligned ? VecABIByteAlign : CurrentByteAlign;
103
104 if (CHAR_BIT * ElemByteSize != ElemBitSize)
105 return false; // Minimum byte-size elements.
106 if (MinAlign(ElemByteSize, CurrentByteAlign) == ElemByteSize) {
107 // Element-aligned, or compatible over-aligned. Keep element-aligned.
108 LoadStore->setAlignment(ElemByteSize);
109 return true;
110 }
111 return false; // Under-aligned.
112 }
113
114 void visitVectorLoadStore(BasicBlock &BB, Instructions &Loads,
115 Instructions &Stores) const;
116 void scalarizeVectorLoadStore(BasicBlock &BB, const Instructions &Loads,
117 const Instructions &Stores) const;
118 };
119 } // anonymous namespace
120
121 char FixVectorLoadStoreAlignment::ID = 0;
122 INITIALIZE_PASS(FixVectorLoadStoreAlignment, "fix-vector-load-store-alignment",
123 "Ensure vector load/store have element-size alignment",
124 false, false)
125
126 void FixVectorLoadStoreAlignment::visitVectorLoadStore(
127 BasicBlock &BB, Instructions &Loads, Instructions &Stores) const {
128 for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE;
129 ++BBI) {
130 Instruction *I = &*BBI;
131 // The following list of instructions is based on mayReadOrWriteMemory.
132 switch (I->getOpcode()) {
133 case Instruction::Load:
134 if (pointerOperandIsVectorPointer<LoadInst>(I)) {
135 if (cast<LoadInst>(I)->isAtomic())
136 report_fatal_error("unhandled: atomic vector store");
137 if (!tryFixVectorAlignment<LoadInst>(DL, I))
138 Loads.push_back(I);
139 }
140 break;
141 case Instruction::Store:
142 if (pointerOperandIsVectorPointer<StoreInst>(I)) {
143 if (cast<StoreInst>(I)->isAtomic())
144 report_fatal_error("unhandled: atomic vector store");
145 if (!tryFixVectorAlignment<StoreInst>(DL, I))
146 Stores.push_back(I);
147 }
148 break;
149 case Instruction::Alloca:
150 case Instruction::Fence:
151 case Instruction::VAArg:
152 // Leave these memory operations as-is, even when they deal with
153 // vectors.
154 break;
155 case Instruction::Call:
156 case Instruction::Invoke:
157 // Call/invoke don't touch memory per-se, leave them as-is.
158 break;
159 case Instruction::AtomicCmpXchg:
160 if (pointerOperandIsVectorPointer<AtomicCmpXchgInst>(I))
161 report_fatal_error(
162 "unhandled: atomic compare and exchange operation on vector");
163 break;
164 case Instruction::AtomicRMW:
165 if (pointerOperandIsVectorPointer<AtomicRMWInst>(I))
166 report_fatal_error("unhandled: atomic RMW operation on vector");
167 break;
168 default:
169 if (I->mayReadOrWriteMemory() && hasVectorPointerOperand(I)) {
170 errs() << "Not handled: " << *I << '\n';
171 report_fatal_error(
172 "unexpected: vector operations which may read/write memory");
173 }
174 break;
175 }
176 }
177 }
178
179 void FixVectorLoadStoreAlignment::scalarizeVectorLoadStore(
180 BasicBlock &BB, const Instructions &Loads,
181 const Instructions &Stores) const {
182 for (Instructions::const_iterator IB = Loads.begin(), IE = Loads.end();
183 IB != IE; ++IB) {
184 LoadInst *VecLoad = cast<LoadInst>(*IB);
185 VectorType *LoadedVecTy =
186 cast<VectorType>(pointerOperandType(VecLoad)->getElementType());
187 Type *ElemTy = LoadedVecTy->getElementType();
188
189 // The base of the vector is as aligned as the vector load (where
190 // zero means ABI alignment for the vector), whereas subsequent
191 // elements are as aligned as the base+offset can be.
192 unsigned BaseAlign = VecLoad->getAlignment()
193 ? VecLoad->getAlignment()
194 : DL->getABITypeAlignment(LoadedVecTy);
195 unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy);
196
197 // Fill in the vector element by element.
198 IRBuilder<> IRB(VecLoad);
199 Value *Loaded = UndefValue::get(LoadedVecTy);
200 Value *Base =
201 IRB.CreateBitCast(VecLoad->getPointerOperand(), ElemTy->getPointerTo());
202
203 for (unsigned Elem = 0, NumElems = LoadedVecTy->getNumElements();
204 Elem != NumElems; ++Elem) {
205 unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem);
206 Value *GEP = IRB.CreateConstInBoundsGEP1_32(Base, Elem);
207 LoadInst *LoadedElem =
208 IRB.CreateAlignedLoad(GEP, Align, VecLoad->isVolatile());
209 LoadedElem->setSynchScope(VecLoad->getSynchScope());
210 Loaded = IRB.CreateInsertElement(
211 Loaded, LoadedElem,
212 ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem));
213 }
214
215 VecLoad->replaceAllUsesWith(Loaded);
216 VecLoad->eraseFromParent();
217 }
218
219 for (Instructions::const_iterator IB = Stores.begin(), IE = Stores.end();
220 IB != IE; ++IB) {
221 StoreInst *VecStore = cast<StoreInst>(*IB);
222 Value *StoredVec = VecStore->getValueOperand();
223 VectorType *StoredVecTy = cast<VectorType>(StoredVec->getType());
224 Type *ElemTy = StoredVecTy->getElementType();
225
226 unsigned BaseAlign = VecStore->getAlignment()
227 ? VecStore->getAlignment()
228 : DL->getABITypeAlignment(StoredVecTy);
229 unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy);
230
231 // Fill in the vector element by element.
232 IRBuilder<> IRB(VecStore);
233 Value *Base = IRB.CreateBitCast(VecStore->getPointerOperand(),
234 ElemTy->getPointerTo());
235
236 for (unsigned Elem = 0, NumElems = StoredVecTy->getNumElements();
237 Elem != NumElems; ++Elem) {
238 unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem);
239 Value *GEP = IRB.CreateConstInBoundsGEP1_32(Base, Elem);
240 Value *ElemToStore = IRB.CreateExtractElement(
241 StoredVec, ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem));
242 StoreInst *StoredElem = IRB.CreateAlignedStore(ElemToStore, GEP, Align,
243 VecStore->isVolatile());
244 StoredElem->setSynchScope(VecStore->getSynchScope());
245 }
246
247 VecStore->eraseFromParent();
248 }
249 }
250
251 bool FixVectorLoadStoreAlignment::runOnBasicBlock(BasicBlock &BB) {
252 bool Changed = false;
253 if (!DL)
254 DL = &getAnalysis<DataLayoutPass>().getDataLayout();
255 Instructions Loads;
256 Instructions Stores;
257 visitVectorLoadStore(BB, Loads, Stores);
258 if (!(Loads.empty() && Stores.empty())) {
259 Changed = true;
260 scalarizeVectorLoadStore(BB, Loads, Stores);
261 }
262 return Changed;
263 }
264
265 BasicBlockPass *llvm::createFixVectorLoadStoreAlignmentPass() {
266 return new FixVectorLoadStoreAlignment();
267 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExpandVarArgs.cpp ('k') | lib/Transforms/NaCl/FlattenGlobals.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698