Chromium Code Reviews| Index: lib/Transforms/NaCl/ConstantInsertExtractElementIndex.cpp |
| diff --git a/lib/Transforms/NaCl/ConstantInsertExtractElementIndex.cpp b/lib/Transforms/NaCl/ConstantInsertExtractElementIndex.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ac70b8efa732466cbec8c5f0e9de1cf1a9790b16 |
| --- /dev/null |
| +++ b/lib/Transforms/NaCl/ConstantInsertExtractElementIndex.cpp |
| @@ -0,0 +1,153 @@ |
| +//===- ConstantInsertExtractElementIndex.cpp - Insert/Extract element -----===// |
| +// |
| +// The LLVM Compiler Infrastructure |
| +// |
| +// This file is distributed under the University of Illinois Open Source |
| +// License. See LICENSE.TXT for details. |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// Transform all InsertElement and ExtractElement with non-constant or |
| +// out-of-bounds indices into stack accesses. This moves all undefined |
| +// behavior to the stack, making InsertElement and ExtractElement |
| +// well-defined. |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#include "llvm/IR/DataLayout.h" |
| +#include "llvm/IR/IRBuilder.h" |
| +#include "llvm/IR/Instruction.h" |
| +#include "llvm/IR/Instructions.h" |
| +#include "llvm/IR/Module.h" |
| +#include "llvm/Pass.h" |
| +#include "llvm/Transforms/NaCl.h" |
| + |
| +#include <algorithm> |
| + |
| +using namespace llvm; |
| + |
| +namespace { |
| +class ConstantInsertExtractElementIndex : public BasicBlockPass { |
| +public: |
| + static char ID; // Pass identification, replacement for typeid |
| + ConstantInsertExtractElementIndex() : BasicBlockPass(ID), M(0), TD(0) { |
| + initializeConstantInsertExtractElementIndexPass( |
| + *PassRegistry::getPassRegistry()); |
| + } |
| + virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
| + AU.addRequired<DataLayout>(); |
| + BasicBlockPass::getAnalysisUsage(AU); |
| + } |
| + virtual bool doInitialization(Module &Mod) { |
| + M = &Mod; |
| + return false; // Unchanged. |
| + } |
| + virtual bool runOnBasicBlock(BasicBlock &BB); |
| + |
| +private: |
| + typedef SmallVector<Instruction *, 8> Instructions; |
| + const Module *M; |
| + const DataLayout *TD; |
|
jvoung (off chromium)
2014/04/04 23:20:21
I think TargetData was renamed to DataLayout. Some
JF
2014/04/15 01:52:27
Done, in this and other files.
|
| + |
| + /// Get the index of an InsertElement or ExtractElement instruction, or null. |
| + static Value *getIdx(const Instruction *I); |
| + |
| + void findInvalidInsertExtractElements(const BasicBlock &BB, |
|
jvoung (off chromium)
2014/04/04 23:20:21
nit: It's not actually invalid so "Invalid" should
JF
2014/04/15 01:52:27
Done.
|
| + Instructions &BadVectorIdx) const; |
| + void fixInvalidInsertExtractElements(BasicBlock &BB, |
| + const Instructions &BadVectorIdx) const; |
| +}; |
| +} |
| + |
| +char ConstantInsertExtractElementIndex::ID = 0; |
| +INITIALIZE_PASS( |
| + ConstantInsertExtractElementIndex, "constant-insert-extract-element-index", |
| + "Force insert and extract vector elemement to always be in bounds", false, |
|
jvoung (off chromium)
2014/04/04 23:20:21
elemement -> element
This doesn't really force th
JF
2014/04/15 01:52:27
Correct. I don't mind doing what you suggest inste
jvoung (off chromium)
2014/04/16 00:10:27
Sure, I'm okay with leaving this as is for now, si
|
| + false) |
| + |
| +Value *ConstantInsertExtractElementIndex::getIdx(const Instruction *I) { |
|
jvoung (off chromium)
2014/04/04 23:20:21
Could have just been a static function that's not
JF
2014/04/15 01:52:27
Done.
|
| + switch (I->getOpcode()) { |
| + default: return 0; |
|
Jim Stichnoth
2014/04/04 23:08:17
I don't know of a style guide reference, but could
JF
2014/04/15 01:52:27
Done.
|
| + case Instruction::InsertElement: return I->getOperand(2); |
| + case Instruction::ExtractElement: return I->getOperand(1); |
| + } |
| +} |
| + |
| +void ConstantInsertExtractElementIndex::findInvalidInsertExtractElements( |
| + const BasicBlock &BB, Instructions &BadVectorIdx) const { |
|
jvoung (off chromium)
2014/04/04 23:20:21
nit: BadVectorIdx sounds like it's a single index,
JF
2014/04/15 01:52:27
Done.
|
| + for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; |
| + ++BBI) { |
| + const Instruction *I = &*BBI; |
| + Value *Idx = getIdx(I); |
| + if (!Idx) |
| + // Not and InsertElement or ExtractElement, ignore the instruction. |
|
Jim Stichnoth
2014/04/04 23:08:17
and --> an
JF
2014/04/15 01:52:27
Done.
|
| + continue; |
| + if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) { |
| + unsigned NumElements = |
| + cast<VectorType>(I->getOperand(0)->getType())->getNumElements(); |
| + if (CI->getValue().ult(NumElements)) |
| + // Index is constant in-range for the vector type, keep as-is. |
| + continue; |
| + } |
| + BadVectorIdx.push_back(const_cast<Instruction *>(I)); |
|
Jim Stichnoth
2014/04/04 23:08:17
I trust const_cast is actually necessary :(
JF
2014/04/15 01:52:27
Yeah, I wanted to go all const-correctness, but so
|
| + } |
| +} |
| + |
| +void ConstantInsertExtractElementIndex::fixInvalidInsertExtractElements( |
| + BasicBlock &BB, const Instructions &BadVectorIdx) const { |
| + for (Instructions::const_iterator IB = BadVectorIdx.begin(), |
| + IE = BadVectorIdx.end(); |
| + IB != IE; ++IB) { |
| + Instruction *I = *IB; |
| + Value *Vec = I->getOperand(0); |
| + Value *Idx = getIdx(I); |
| + VectorType *VecTy = cast<VectorType>(Vec->getType()); |
| + Type *ElemTy = VecTy->getElementType(); |
| + unsigned ElemAlign = TD->getPrefTypeAlignment(ElemTy); |
| + unsigned VecAlign = std::max(ElemAlign, TD->getPrefTypeAlignment(VecTy)); |
| + |
| + IRBuilder<> IRB(I); |
| + AllocaInst *Alloca = IRB.CreateAlloca( |
| + ElemTy, ConstantInt::get(Type::getInt32Ty(M->getContext()), |
|
jvoung (off chromium)
2014/04/04 23:20:21
Instead of ElemTy, have the alloca be i8, and mult
jvoung (off chromium)
2014/04/07 15:40:11
n/m about this point -- it'll be handled by the Re
JF
2014/04/15 01:52:27
Yeah I wanted to do the "right" thing for LLVM, an
|
| + VecTy->getNumElements())); |
| + Alloca->setAlignment(VecAlign); |
| + Value *AllocaAsVec = IRB.CreateBitCast(Alloca, VecTy->getPointerTo()); |
| + IRB.CreateAlignedStore(Vec, AllocaAsVec, Alloca->getAlignment()); |
| + Value *GEP = IRB.CreateGEP(Alloca, Idx); |
| + |
| + Value *Res; |
| + switch (I->getOpcode()) { |
| + default: |
| + llvm_unreachable("expected InsertElement or ExtractElement"); |
| + case Instruction::InsertElement: { |
| + IRB.CreateAlignedStore(I->getOperand(1), GEP, ElemAlign); |
| + Res = IRB.CreateAlignedLoad(AllocaAsVec, Alloca->getAlignment()); |
| + break; |
| + } |
| + case Instruction::ExtractElement: { |
| + Res = IRB.CreateAlignedLoad(GEP, ElemAlign); |
| + break; |
| + } |
| + } |
|
Jim Stichnoth
2014/04/04 23:08:17
Sorry, these two perfectly aligned braces really b
JF
2014/04/15 01:52:27
Done, though if they *had* been required I'd have
|
| + |
| + I->replaceAllUsesWith(Res); |
|
jvoung (off chromium)
2014/04/04 23:20:21
CopyDebug?
JF
2014/04/15 01:52:27
I was going to fix IRBuilder instead so it copies
|
| + I->eraseFromParent(); |
| + } |
| +} |
| + |
| +bool ConstantInsertExtractElementIndex::runOnBasicBlock(BasicBlock &BB) { |
| + bool Changed = false; |
| + if (!TD) |
| + TD = &getAnalysis<DataLayout>(); |
| + Instructions BadVectorIdx; |
| + findInvalidInsertExtractElements(BB, BadVectorIdx); |
| + if (!BadVectorIdx.empty()) { |
| + Changed = true; |
| + fixInvalidInsertExtractElements(BB, BadVectorIdx); |
| + } |
| + return Changed; |
| +} |
| + |
| +BasicBlockPass *llvm::createConstantInsertExtractElementIndexPass() { |
| + return new ConstantInsertExtractElementIndex(); |
| +} |