Chromium Code Reviews| 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 |