Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1002)

Unified Diff: lib/Transforms/NaCl/BackendCanonicalize.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/AddPNaClExternalDecls.cpp ('k') | lib/Transforms/NaCl/CMakeLists.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/BackendCanonicalize.cpp
diff --git a/lib/Transforms/NaCl/BackendCanonicalize.cpp b/lib/Transforms/NaCl/BackendCanonicalize.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d1d4ffcd679ac0f14fc147a7782b7f846a1c1d4
--- /dev/null
+++ b/lib/Transforms/NaCl/BackendCanonicalize.cpp
@@ -0,0 +1,361 @@
+//===- BackendCanonicalize.cpp --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Clean up some toolchain-side PNaCl ABI simplification passes. These passes
+// allow PNaCl to have a simple and stable ABI, but they sometimes lead to
+// harder-to-optimize code. This is desirable because LLVM's definition of
+// "canonical" evolves over time, meaning that PNaCl's simple ABI can stay
+// simple yet still take full advantage of LLVM's backend by having this pass
+// massage the code into something that the backend prefers handling.
+//
+// It currently:
+// - Re-generates shufflevector (not part of the PNaCl ABI) from insertelement /
+// extractelement combinations. This is done by duplicating some of
+// instcombine's implementation, and ignoring optimizations that should
+// already have taken place.
+// - Re-materializes constant loads, especially of vectors. This requires doing
+// constant folding through bitcasts.
+//
+// The pass also performs limited DCE on instructions it knows to be dead,
+// instead of performing a full global DCE.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/ConstantFolding.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/Pass.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/NaCl.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+
+// =============================================================================
+// TODO(jfb) The following functions are as-is from instcombine. Make them
+// reusable instead.
+
+/// CollectSingleShuffleElements - If V is a shuffle of values that ONLY returns
+/// elements from either LHS or RHS, return the shuffle mask and true.
+/// Otherwise, return false.
+static bool CollectSingleShuffleElements(Value *V, Value *LHS, Value *RHS,
+ SmallVectorImpl<Constant*> &Mask) {
+ assert(LHS->getType() == RHS->getType() &&
+ "Invalid CollectSingleShuffleElements");
+ unsigned NumElts = V->getType()->getVectorNumElements();
+
+ if (isa<UndefValue>(V)) {
+ Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext())));
+ return true;
+ }
+
+ if (V == LHS) {
+ for (unsigned i = 0; i != NumElts; ++i)
+ Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i));
+ return true;
+ }
+
+ if (V == RHS) {
+ for (unsigned i = 0; i != NumElts; ++i)
+ Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ i+NumElts));
+ return true;
+ }
+
+ if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) {
+ // If this is an insert of an extract from some other vector, include it.
+ Value *VecOp = IEI->getOperand(0);
+ Value *ScalarOp = IEI->getOperand(1);
+ Value *IdxOp = IEI->getOperand(2);
+
+ if (!isa<ConstantInt>(IdxOp))
+ return false;
+ unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
+
+ if (isa<UndefValue>(ScalarOp)) { // inserting undef into vector.
+ // We can handle this if the vector we are inserting into is
+ // transitively ok.
+ if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) {
+ // If so, update the mask to reflect the inserted undef.
+ Mask[InsertedIdx] = UndefValue::get(Type::getInt32Ty(V->getContext()));
+ return true;
+ }
+ } else if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)){
+ if (isa<ConstantInt>(EI->getOperand(1))) {
+ unsigned ExtractedIdx =
+ cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
+ unsigned NumLHSElts = LHS->getType()->getVectorNumElements();
+
+ // This must be extracting from either LHS or RHS.
+ if (EI->getOperand(0) == LHS || EI->getOperand(0) == RHS) {
+ // We can handle this if the vector we are inserting into is
+ // transitively ok.
+ if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) {
+ // If so, update the mask to reflect the inserted value.
+ if (EI->getOperand(0) == LHS) {
+ Mask[InsertedIdx % NumElts] =
+ ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ ExtractedIdx);
+ } else {
+ assert(EI->getOperand(0) == RHS);
+ Mask[InsertedIdx % NumElts] =
+ ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ ExtractedIdx + NumLHSElts);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/// We are building a shuffle to create V, which is a sequence of insertelement,
+/// extractelement pairs. If PermittedRHS is set, then we must either use it or
+/// not rely on the second vector source. Return a std::pair containing the
+/// left and right vectors of the proposed shuffle (or 0), and set the Mask
+/// parameter as required.
+///
+/// Note: we intentionally don't try to fold earlier shuffles since they have
+/// often been chosen carefully to be efficiently implementable on the target.
+typedef std::pair<Value *, Value *> ShuffleOps;
+
+static ShuffleOps CollectShuffleElements(Value *V,
+ SmallVectorImpl<Constant *> &Mask,
+ Value *PermittedRHS) {
+ assert(V->getType()->isVectorTy() && "Invalid shuffle!");
+ unsigned NumElts = cast<VectorType>(V->getType())->getNumElements();
+
+ if (isa<UndefValue>(V)) {
+ Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext())));
+ return std::make_pair(
+ PermittedRHS ? UndefValue::get(PermittedRHS->getType()) : V, nullptr);
+ }
+
+ if (isa<ConstantAggregateZero>(V)) {
+ Mask.assign(NumElts, ConstantInt::get(Type::getInt32Ty(V->getContext()),0));
+ return std::make_pair(V, nullptr);
+ }
+
+ if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) {
+ // If this is an insert of an extract from some other vector, include it.
+ Value *VecOp = IEI->getOperand(0);
+ Value *ScalarOp = IEI->getOperand(1);
+ Value *IdxOp = IEI->getOperand(2);
+
+ if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) {
+ if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) {
+ unsigned ExtractedIdx =
+ cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
+ unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
+
+ // Either the extracted from or inserted into vector must be RHSVec,
+ // otherwise we'd end up with a shuffle of three inputs.
+ if (EI->getOperand(0) == PermittedRHS || PermittedRHS == nullptr) {
+ Value *RHS = EI->getOperand(0);
+ ShuffleOps LR = CollectShuffleElements(VecOp, Mask, RHS);
+ assert(LR.second == nullptr || LR.second == RHS);
+
+ if (LR.first->getType() != RHS->getType()) {
+ // We tried our best, but we can't find anything compatible with RHS
+ // further up the chain. Return a trivial shuffle.
+ for (unsigned i = 0; i < NumElts; ++i)
+ Mask[i] = ConstantInt::get(Type::getInt32Ty(V->getContext()), i);
+ return std::make_pair(V, nullptr);
+ }
+
+ unsigned NumLHSElts = RHS->getType()->getVectorNumElements();
+ Mask[InsertedIdx % NumElts] =
+ ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ NumLHSElts+ExtractedIdx);
+ return std::make_pair(LR.first, RHS);
+ }
+
+ if (VecOp == PermittedRHS) {
+ // We've gone as far as we can: anything on the other side of the
+ // extractelement will already have been converted into a shuffle.
+ unsigned NumLHSElts =
+ EI->getOperand(0)->getType()->getVectorNumElements();
+ for (unsigned i = 0; i != NumElts; ++i)
+ Mask.push_back(ConstantInt::get(
+ Type::getInt32Ty(V->getContext()),
+ i == InsertedIdx ? ExtractedIdx : NumLHSElts + i));
+ return std::make_pair(EI->getOperand(0), PermittedRHS);
+ }
+
+ // If this insertelement is a chain that comes from exactly these two
+ // vectors, return the vector and the effective shuffle.
+ if (EI->getOperand(0)->getType() == PermittedRHS->getType() &&
+ CollectSingleShuffleElements(IEI, EI->getOperand(0), PermittedRHS,
+ Mask))
+ return std::make_pair(EI->getOperand(0), PermittedRHS);
+ }
+ }
+ }
+
+ // Otherwise, can't do anything fancy. Return an identity vector.
+ for (unsigned i = 0; i != NumElts; ++i)
+ Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i));
+ return std::make_pair(V, nullptr);
+}
+
+// =============================================================================
+
+
+namespace {
+
+class BackendCanonicalize : public FunctionPass,
+ public InstVisitor<BackendCanonicalize, bool> {
+public:
+ static char ID; // Pass identification, replacement for typeid
+ BackendCanonicalize() : FunctionPass(ID), DL(0), TLI(0) {
+ initializeBackendCanonicalizePass(*PassRegistry::getPassRegistry());
+ }
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<DataLayoutPass>();
+ AU.addRequired<TargetLibraryInfo>();
+ FunctionPass::getAnalysisUsage(AU);
+ }
+
+ virtual bool runOnFunction(Function &F);
+
+ // InstVisitor implementation. Unhandled instructions stay as-is.
+ bool visitInstruction(Instruction &I) { return false; }
+ bool visitInsertElementInst(InsertElementInst &IE);
+ bool visitBitCastInst(BitCastInst &C);
+ bool visitLoadInst(LoadInst &L);
+
+private:
+ const DataLayout *DL;
+ const TargetLibraryInfo *TLI;
+
+ // List of instructions that are now obsolete, and should be DCE'd.
+ typedef SmallVector<Instruction *, 512> KillList;
+ KillList Kill;
+
+ /// Helper that constant folds an instruction.
+ bool visitConstantFoldableInstruction(Instruction *I);
+
+ /// Empty the kill list, making sure that all other dead instructions
+ /// up the chain (but in the current basic block) also get killed.
+ static void emptyKillList(KillList &Kill);
+};
+
+} // anonymous namespace
+
+char BackendCanonicalize::ID = 0;
+INITIALIZE_PASS(BackendCanonicalize, "backend-canonicalize",
+ "Canonicalize PNaCl bitcode for LLVM backends", false, false)
+
+bool BackendCanonicalize::runOnFunction(Function &F) {
+ bool Modified = false;
+ DL = &getAnalysis<DataLayoutPass>().getDataLayout();
+ TLI = &getAnalysis<TargetLibraryInfo>();
+
+ for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
+ for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
+ Modified |= visit(&*BI);
+ emptyKillList(Kill);
+ return Modified;
+}
+
+// This function is *almost* as-is from instcombine, avoiding silly
+// cases that should already have been optimized.
+bool BackendCanonicalize::visitInsertElementInst(InsertElementInst &IE) {
+ Value *ScalarOp = IE.getOperand(1);
+ Value *IdxOp = IE.getOperand(2);
+
+ // If the inserted element was extracted from some other vector, and if the
+ // indexes are constant, try to turn this into a shufflevector operation.
+ if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) {
+ if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) {
+ unsigned NumInsertVectorElts = IE.getType()->getNumElements();
+ unsigned NumExtractVectorElts =
+ EI->getOperand(0)->getType()->getVectorNumElements();
+ unsigned ExtractedIdx =
+ cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
+ unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
+
+ if (ExtractedIdx >= NumExtractVectorElts) // Out of range extract.
+ return false;
+
+ if (InsertedIdx >= NumInsertVectorElts) // Out of range insert.
+ return false;
+
+ // If this insertelement isn't used by some other insertelement, turn it
+ // (and any insertelements it points to), into one big shuffle.
+ if (!IE.hasOneUse() || !isa<InsertElementInst>(IE.user_back())) {
+ typedef SmallVector<Constant *, 16> MaskT;
+ MaskT Mask;
+ Value *LHS, *RHS;
+ std::tie(LHS, RHS) = CollectShuffleElements(&IE, Mask, nullptr);
+ if (!RHS)
+ RHS = UndefValue::get(LHS->getType());
+ // We now have a shuffle of LHS, RHS, Mask.
+
+ if (isa<UndefValue>(LHS) && !isa<UndefValue>(RHS)) {
+ // Canonicalize shufflevector to always have undef on the RHS,
+ // and adjust the mask.
+ std::swap(LHS, RHS);
+ for (MaskT::iterator I = Mask.begin(), E = Mask.end(); I != E; ++I) {
+ unsigned Idx = cast<ConstantInt>(*I)->getZExtValue();
+ unsigned NewIdx = Idx >= NumInsertVectorElts
+ ? Idx - NumInsertVectorElts
+ : Idx + NumInsertVectorElts;
+ *I = ConstantInt::get(Type::getInt32Ty(RHS->getContext()), NewIdx);
+ }
+ }
+
+ IRBuilder<> IRB(&IE);
+ IE.replaceAllUsesWith(
+ IRB.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)));
+ // The chain of now-dead insertelement / extractelement
+ // instructions can be deleted.
+ Kill.push_back(&IE);
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BackendCanonicalize::visitBitCastInst(BitCastInst &B) {
+ return visitConstantFoldableInstruction(&B);
+}
+
+bool BackendCanonicalize::visitLoadInst(LoadInst &L) {
+ return visitConstantFoldableInstruction(&L);
+}
+
+bool BackendCanonicalize::visitConstantFoldableInstruction(Instruction *I) {
+ if (Constant *Folded = ConstantFoldInstruction(I, DL, TLI)) {
+ I->replaceAllUsesWith(Folded);
+ Kill.push_back(I);
+ return true;
+ }
+ return false;
+}
+
+void BackendCanonicalize::emptyKillList(KillList &Kill) {
+ while (!Kill.empty())
+ RecursivelyDeleteTriviallyDeadInstructions(Kill.pop_back_val());
+}
+
+FunctionPass *llvm::createBackendCanonicalizePass() {
+ return new BackendCanonicalize();
+}
« no previous file with comments | « lib/Transforms/NaCl/AddPNaClExternalDecls.cpp ('k') | lib/Transforms/NaCl/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698