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 // 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 } |
OLD | NEW |