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 void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 38 AU.addRequired<DataLayoutPass>(); |
| 39 BasicBlockPass::getAnalysisUsage(AU); |
| 40 } |
| 41 using BasicBlockPass::doInitialization; |
| 42 bool doInitialization(Module &Mod) override { |
| 43 M = &Mod; |
| 44 return false; // Unchanged. |
| 45 } |
| 46 bool runOnBasicBlock(BasicBlock &BB) override; |
| 47 |
| 48 private: |
| 49 typedef SmallVector<Instruction *, 8> Instructions; |
| 50 const Module *M; |
| 51 const DataLayout *DL; |
| 52 |
| 53 void findNonConstantInsertExtractElements( |
| 54 const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, |
| 55 Instructions &NonConstantVectorIndices) const; |
| 56 void fixOutOfRangeConstantIndices(BasicBlock &BB, |
| 57 const Instructions &Instrs) const; |
| 58 void fixNonConstantVectorIndices(BasicBlock &BB, |
| 59 const Instructions &Instrs) const; |
| 60 }; |
| 61 |
| 62 /// Number of elements in a vector instruction. |
| 63 unsigned vectorNumElements(const Instruction *I) { |
| 64 return cast<VectorType>(I->getOperand(0)->getType())->getNumElements(); |
| 65 } |
| 66 |
| 67 /// Get the index of an InsertElement or ExtractElement instruction, or null. |
| 68 Value *getInsertExtractElementIdx(const Instruction *I) { |
| 69 switch (I->getOpcode()) { |
| 70 default: return NULL; |
| 71 case Instruction::InsertElement: return I->getOperand(2); |
| 72 case Instruction::ExtractElement: return I->getOperand(1); |
| 73 } |
| 74 } |
| 75 |
| 76 /// Set the index of an InsertElement or ExtractElement instruction. |
| 77 void setInsertExtractElementIdx(Instruction *I, Value *NewIdx) { |
| 78 switch (I->getOpcode()) { |
| 79 default: |
| 80 llvm_unreachable( |
| 81 "expected instruction to be InsertElement or ExtractElement"); |
| 82 case Instruction::InsertElement: I->setOperand(2, NewIdx); break; |
| 83 case Instruction::ExtractElement: I->setOperand(1, NewIdx); break; |
| 84 } |
| 85 } |
| 86 } // anonymous namespace |
| 87 |
| 88 char ConstantInsertExtractElementIndex::ID = 0; |
| 89 INITIALIZE_PASS( |
| 90 ConstantInsertExtractElementIndex, "constant-insert-extract-element-index", |
| 91 "Force insert and extract vector element to always be in bounds", false, |
| 92 false) |
| 93 |
| 94 void ConstantInsertExtractElementIndex::findNonConstantInsertExtractElements( |
| 95 const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, |
| 96 Instructions &NonConstantVectorIndices) const { |
| 97 for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; |
| 98 ++BBI) { |
| 99 const Instruction *I = &*BBI; |
| 100 if (Value *Idx = getInsertExtractElementIdx(I)) { |
| 101 if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) { |
| 102 if (!CI->getValue().ult(vectorNumElements(I))) |
| 103 OutOfRangeConstantIndices.push_back(const_cast<Instruction *>(I)); |
| 104 } else |
| 105 NonConstantVectorIndices.push_back(const_cast<Instruction *>(I)); |
| 106 } |
| 107 } |
| 108 } |
| 109 |
| 110 void ConstantInsertExtractElementIndex::fixOutOfRangeConstantIndices( |
| 111 BasicBlock &BB, const Instructions &Instrs) const { |
| 112 for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); |
| 113 IB != IE; ++IB) { |
| 114 Instruction *I = *IB; |
| 115 const APInt &Idx = |
| 116 cast<ConstantInt>(getInsertExtractElementIdx(I))->getValue(); |
| 117 APInt NumElements = APInt(Idx.getBitWidth(), vectorNumElements(I)); |
| 118 APInt NewIdx = Idx.urem(NumElements); |
| 119 setInsertExtractElementIdx(I, ConstantInt::get(M->getContext(), NewIdx)); |
| 120 } |
| 121 } |
| 122 |
| 123 void ConstantInsertExtractElementIndex::fixNonConstantVectorIndices( |
| 124 BasicBlock &BB, const Instructions &Instrs) const { |
| 125 for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); |
| 126 IB != IE; ++IB) { |
| 127 Instruction *I = *IB; |
| 128 Value *Vec = I->getOperand(0); |
| 129 Value *Idx = getInsertExtractElementIdx(I); |
| 130 VectorType *VecTy = cast<VectorType>(Vec->getType()); |
| 131 Type *ElemTy = VecTy->getElementType(); |
| 132 unsigned ElemAlign = DL->getPrefTypeAlignment(ElemTy); |
| 133 unsigned VecAlign = std::max(ElemAlign, DL->getPrefTypeAlignment(VecTy)); |
| 134 |
| 135 IRBuilder<> IRB(I); |
| 136 AllocaInst *Alloca = IRB.CreateAlloca( |
| 137 ElemTy, ConstantInt::get(Type::getInt32Ty(M->getContext()), |
| 138 vectorNumElements(I))); |
| 139 Alloca->setAlignment(VecAlign); |
| 140 Value *AllocaAsVec = IRB.CreateBitCast(Alloca, VecTy->getPointerTo()); |
| 141 IRB.CreateAlignedStore(Vec, AllocaAsVec, Alloca->getAlignment()); |
| 142 Value *GEP = IRB.CreateGEP(Alloca, Idx); |
| 143 |
| 144 Value *Res; |
| 145 switch (I->getOpcode()) { |
| 146 default: |
| 147 llvm_unreachable("expected InsertElement or ExtractElement"); |
| 148 case Instruction::InsertElement: |
| 149 IRB.CreateAlignedStore(I->getOperand(1), GEP, ElemAlign); |
| 150 Res = IRB.CreateAlignedLoad(AllocaAsVec, Alloca->getAlignment()); |
| 151 break; |
| 152 case Instruction::ExtractElement: |
| 153 Res = IRB.CreateAlignedLoad(GEP, ElemAlign); |
| 154 break; |
| 155 } |
| 156 |
| 157 I->replaceAllUsesWith(Res); |
| 158 I->eraseFromParent(); |
| 159 } |
| 160 } |
| 161 |
| 162 bool ConstantInsertExtractElementIndex::runOnBasicBlock(BasicBlock &BB) { |
| 163 bool Changed = false; |
| 164 if (!DL) |
| 165 DL = &getAnalysis<DataLayoutPass>().getDataLayout(); |
| 166 Instructions OutOfRangeConstantIndices; |
| 167 Instructions NonConstantVectorIndices; |
| 168 |
| 169 findNonConstantInsertExtractElements(BB, OutOfRangeConstantIndices, |
| 170 NonConstantVectorIndices); |
| 171 if (!OutOfRangeConstantIndices.empty()) { |
| 172 Changed = true; |
| 173 fixOutOfRangeConstantIndices(BB, OutOfRangeConstantIndices); |
| 174 } |
| 175 if (!NonConstantVectorIndices.empty()) { |
| 176 Changed = true; |
| 177 fixNonConstantVectorIndices(BB, NonConstantVectorIndices); |
| 178 } |
| 179 return Changed; |
| 180 } |
| 181 |
| 182 BasicBlockPass *llvm::createConstantInsertExtractElementIndexPass() { |
| 183 return new ConstantInsertExtractElementIndex(); |
| 184 } |
OLD | NEW |