OLD | NEW |
(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 // Replace all vector load/store instructions by loads/stores of each |
| 11 // individual element since different architectures have different |
| 12 // faults on unaligned memory access. This pass pessimizes all vector |
| 13 // memory accesses. It's expected that backends with more liberal |
| 14 // alignment restrictions recognize this pattern and reconstruct the |
| 15 // original vector load/store. |
| 16 // |
| 17 // Volatile load/store are broken up as allowed by C/C++, and atomic |
| 18 // accesses cause errors at compile-time. |
| 19 // |
| 20 //===----------------------------------------------------------------------===// |
| 21 |
| 22 #include "llvm/IR/DataLayout.h" |
| 23 #include "llvm/IR/IRBuilder.h" |
| 24 #include "llvm/IR/Instruction.h" |
| 25 #include "llvm/IR/Instructions.h" |
| 26 #include "llvm/IR/Module.h" |
| 27 #include "llvm/Pass.h" |
| 28 #include "llvm/Support/Debug.h" |
| 29 #include "llvm/Support/MathExtras.h" |
| 30 #include "llvm/Transforms/NaCl.h" |
| 31 |
| 32 using namespace llvm; |
| 33 |
| 34 namespace { |
| 35 class FixVectorLoadStoreAlignment : public BasicBlockPass { |
| 36 public: |
| 37 static char ID; // Pass identification, replacement for typeid |
| 38 FixVectorLoadStoreAlignment() : BasicBlockPass(ID), M(0), DL(0) { |
| 39 initializeFixVectorLoadStoreAlignmentPass(*PassRegistry::getPassRegistry()); |
| 40 } |
| 41 virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
| 42 AU.addRequired<DataLayout>(); |
| 43 BasicBlockPass::getAnalysisUsage(AU); |
| 44 } |
| 45 virtual bool doInitialization(Module &Mod) { |
| 46 M = &Mod; |
| 47 return false; // Unchanged. |
| 48 } |
| 49 virtual bool runOnBasicBlock(BasicBlock &BB); |
| 50 |
| 51 private: |
| 52 typedef SmallVector<Instruction *, 8> Instructions; |
| 53 const Module *M; |
| 54 const DataLayout *DL; |
| 55 |
| 56 /// Some sub-classes of Instruction have a non-virtual function |
| 57 /// indicating which operand is the pointer operand. This template |
| 58 /// function returns the pointer operand's type, and requires that |
| 59 /// InstTy have a getPointerOperand function. |
| 60 template <typename InstTy> |
| 61 static PointerType *pointerOperandType(const InstTy *I) { |
| 62 return cast<PointerType>(I->getPointerOperand()->getType()); |
| 63 } |
| 64 |
| 65 /// Similar to pointerOperandType, this template function checks |
| 66 /// whether the pointer operand is a pointer to a vector type. |
| 67 template <typename InstTy> |
| 68 static bool pointerOperandIsVectorPointer(const Instruction *I) { |
| 69 return pointerOperandType(cast<InstTy>(I))->getElementType()->isVectorTy(); |
| 70 } |
| 71 |
| 72 /// Returns true if one of the Instruction's operands is a pointer to |
| 73 /// a vector type. This is more general than the above and assumes we |
| 74 /// don't know which Instruction type is provided. |
| 75 static bool hasVectorPointerOperand(const Instruction *I) { |
| 76 for (User::const_op_iterator IB = I->op_begin(), IE = I->op_end(); IB != IE; |
| 77 ++IB) |
| 78 if (PointerType *PtrTy = dyn_cast<PointerType>((*IB)->getType())) |
| 79 if (isa<VectorType>(PtrTy->getElementType())) |
| 80 return true; |
| 81 return false; |
| 82 } |
| 83 |
| 84 void findVectorLoadStore(const BasicBlock &BB, Instructions &Loads, |
| 85 Instructions &Stores) const; |
| 86 void fixVectorLoadStoreAlignment(BasicBlock &BB, const Instructions &Loads, |
| 87 const Instructions &Stores) const; |
| 88 }; |
| 89 } // anonymous namespace |
| 90 |
| 91 char FixVectorLoadStoreAlignment::ID = 0; |
| 92 INITIALIZE_PASS(FixVectorLoadStoreAlignment, "fix-vector-load-store-alignment", |
| 93 "Replace vector load/store by loads/stores of each element", |
| 94 false, false) |
| 95 |
| 96 void FixVectorLoadStoreAlignment::findVectorLoadStore( |
| 97 const BasicBlock &BB, Instructions &Loads, Instructions &Stores) const { |
| 98 for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; |
| 99 ++BBI) { |
| 100 Instruction *I = const_cast<Instruction *>(&*BBI); |
| 101 // The following list of instructions is based on mayReadOrWriteMemory. |
| 102 switch (I->getOpcode()) { |
| 103 case Instruction::Load: |
| 104 if (pointerOperandIsVectorPointer<LoadInst>(I)) { |
| 105 if (cast<LoadInst>(I)->isAtomic()) |
| 106 report_fatal_error("unhandled: atomic vector store"); |
| 107 Loads.push_back(I); |
| 108 } |
| 109 break; |
| 110 case Instruction::Store: |
| 111 if (pointerOperandIsVectorPointer<StoreInst>(I)) { |
| 112 if (cast<StoreInst>(I)->isAtomic()) |
| 113 report_fatal_error("unhandled: atomic vector store"); |
| 114 Stores.push_back(I); |
| 115 } |
| 116 break; |
| 117 case Instruction::Alloca: |
| 118 case Instruction::Fence: |
| 119 case Instruction::VAArg: |
| 120 // Leave these memory operations as-is, even when they deal with |
| 121 // vectors. |
| 122 break; |
| 123 case Instruction::Call: |
| 124 case Instruction::Invoke: |
| 125 // Call/invoke don't touch memory per-se, leave them as-is. |
| 126 break; |
| 127 case Instruction::AtomicCmpXchg: |
| 128 if (pointerOperandIsVectorPointer<AtomicCmpXchgInst>(I)) |
| 129 report_fatal_error( |
| 130 "unhandled: atomic compare and exchange operation on vector"); |
| 131 break; |
| 132 case Instruction::AtomicRMW: |
| 133 if (pointerOperandIsVectorPointer<AtomicRMWInst>(I)) |
| 134 report_fatal_error("unhandled: atomic RMW operation on vector"); |
| 135 break; |
| 136 default: |
| 137 if (I->mayReadOrWriteMemory() && hasVectorPointerOperand(I)) { |
| 138 errs() << "Not handled: " << *I << '\n'; |
| 139 report_fatal_error( |
| 140 "unexpected: vector operations which may read/write memory"); |
| 141 } |
| 142 break; |
| 143 } |
| 144 } |
| 145 } |
| 146 |
| 147 void FixVectorLoadStoreAlignment::fixVectorLoadStoreAlignment( |
| 148 BasicBlock &BB, const Instructions &Loads, |
| 149 const Instructions &Stores) const { |
| 150 for (Instructions::const_iterator IB = Loads.begin(), IE = Loads.end(); |
| 151 IB != IE; ++IB) { |
| 152 LoadInst *VecLoad = cast<LoadInst>(*IB); |
| 153 VectorType *LoadedVecTy = |
| 154 cast<VectorType>(pointerOperandType(VecLoad)->getElementType()); |
| 155 Type *ElemTy = LoadedVecTy->getElementType(); |
| 156 |
| 157 // The base of the vector is as aligned as the vector load (where |
| 158 // zero means ABI alignment for the vector), whereas subsequent |
| 159 // elements are as aligned as the base+offset can be. |
| 160 unsigned BaseAlign = VecLoad->getAlignment() |
| 161 ? VecLoad->getAlignment() |
| 162 : DL->getABITypeAlignment(LoadedVecTy); |
| 163 unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy); |
| 164 |
| 165 // Fill in the vector element by element. |
| 166 IRBuilder<> IRB(VecLoad); |
| 167 Value *Loaded = UndefValue::get(LoadedVecTy); |
| 168 Value *Base = |
| 169 IRB.CreateBitCast(VecLoad->getPointerOperand(), ElemTy->getPointerTo()); |
| 170 |
| 171 for (unsigned Elem = 0, NumElems = LoadedVecTy->getNumElements(); |
| 172 Elem != NumElems; ++Elem) { |
| 173 unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem); |
| 174 Value *GEP = IRB.CreateConstInBoundsGEP1_32(Base, Elem); |
| 175 LoadInst *LoadedElem = |
| 176 IRB.CreateAlignedLoad(GEP, Align, VecLoad->isVolatile()); |
| 177 LoadedElem->setSynchScope(VecLoad->getSynchScope()); |
| 178 Loaded = IRB.CreateInsertElement( |
| 179 Loaded, LoadedElem, |
| 180 ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem)); |
| 181 } |
| 182 |
| 183 VecLoad->replaceAllUsesWith(Loaded); |
| 184 VecLoad->eraseFromParent(); |
| 185 } |
| 186 |
| 187 for (Instructions::const_iterator IB = Stores.begin(), IE = Stores.end(); |
| 188 IB != IE; ++IB) { |
| 189 StoreInst *VecStore = cast<StoreInst>(*IB); |
| 190 Value *StoredVec = VecStore->getValueOperand(); |
| 191 VectorType *StoredVecTy = cast<VectorType>(StoredVec->getType()); |
| 192 Type *ElemTy = StoredVecTy->getElementType(); |
| 193 |
| 194 unsigned BaseAlign = VecStore->getAlignment() |
| 195 ? VecStore->getAlignment() |
| 196 : DL->getABITypeAlignment(StoredVecTy); |
| 197 unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy); |
| 198 |
| 199 // Fill in the vector element by element. |
| 200 IRBuilder<> IRB(VecStore); |
| 201 Value *Base = IRB.CreateBitCast(VecStore->getPointerOperand(), |
| 202 ElemTy->getPointerTo()); |
| 203 |
| 204 for (unsigned Elem = 0, NumElems = StoredVecTy->getNumElements(); |
| 205 Elem != NumElems; ++Elem) { |
| 206 unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem); |
| 207 Value *GEP = IRB.CreateConstInBoundsGEP1_32(Base, Elem); |
| 208 Value *ElemToStore = IRB.CreateExtractElement( |
| 209 StoredVec, ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem)); |
| 210 StoreInst *StoredElem = IRB.CreateAlignedStore(ElemToStore, GEP, Align, |
| 211 VecStore->isVolatile()); |
| 212 StoredElem->setSynchScope(VecStore->getSynchScope()); |
| 213 } |
| 214 |
| 215 VecStore->eraseFromParent(); |
| 216 } |
| 217 } |
| 218 |
| 219 bool FixVectorLoadStoreAlignment::runOnBasicBlock(BasicBlock &BB) { |
| 220 bool Changed = false; |
| 221 if (!DL) |
| 222 DL = &getAnalysis<DataLayout>(); |
| 223 Instructions Loads; |
| 224 Instructions Stores; |
| 225 findVectorLoadStore(BB, Loads, Stores); |
| 226 if (!(Loads.empty() && Stores.empty())) { |
| 227 Changed = true; |
| 228 fixVectorLoadStoreAlignment(BB, Loads, Stores); |
| 229 } |
| 230 return Changed; |
| 231 } |
| 232 |
| 233 BasicBlockPass *llvm::createFixVectorLoadStoreAlignmentPass() { |
| 234 return new FixVectorLoadStoreAlignment(); |
| 235 } |
OLD | NEW |