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

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

Issue 282553003: PNaCl translator: combine insertelement / extractelement patterns generated by the toolchain into s… (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Fix typo on canonicalization range. Created 6 years, 7 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/CMakeLists.txt ('k') | lib/Transforms/NaCl/ExpandShuffleVector.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/CombineVectorInstructions.cpp
diff --git a/lib/Transforms/NaCl/CombineVectorInstructions.cpp b/lib/Transforms/NaCl/CombineVectorInstructions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ca5f5d2c170262e207c8d768ade3db640d95718
--- /dev/null
+++ b/lib/Transforms/NaCl/CombineVectorInstructions.cpp
@@ -0,0 +1,279 @@
+//===- CombineVectorInstructions.cpp --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass cleans up some of the toolchain-side PNaCl ABI
+// simplification passes relating to vectors. These passes allow PNaCl
+// to have a simple and stable ABI, but they sometimes lead to
+// harder-to-optimize code.
+//
+// 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.
+// - TODO(jfb) Re-combine load/store for vectors, which are transformed
+// into load/store of the underlying elements.
+// - TODO(jfb) Re-materialize constant arguments, which are currently
+// loads from global constant vectors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/InstVisitor.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+namespace {
+// TODO(jfb) This function is as-is from instcombine.
Derek Schuff 2014/05/12 20:49:22 there's nothing to do specified in this TODO.
JF 2014/05/12 22:00:01 Done.
+//
+/// 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.
+bool CollectSingleShuffleElements(Value *V, Value *LHS, Value *RHS,
+ SmallVectorImpl<Constant*> &Mask) {
+ assert(V->getType() == LHS->getType() && V->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.
+ // Okay, we can handle this if the vector we are insertinting 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)) &&
+ EI->getOperand(0)->getType() == V->getType()) {
+ unsigned ExtractedIdx =
+ cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
+
+ // This must be extracting from either LHS or RHS.
+ if (EI->getOperand(0) == LHS || EI->getOperand(0) == RHS) {
+ // Okay, we can handle this if the vector we are insertinting 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+NumElts);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ // TODO: Handle shufflevector here!
+
+ return false;
+}
+
+// TODO(jfb) This function is as-is from instcombine.
+//
+/// CollectShuffleElements - We are building a shuffle of V, using RHS as the
+/// RHS of the shuffle instruction, if it is not null. Return a shuffle mask
+/// that computes V and the LHS value of the shuffle.
+Value *CollectShuffleElements(Value *V, SmallVectorImpl<Constant*> &Mask,
+ Value *&RHS) {
+ assert(V->getType()->isVectorTy() &&
+ (RHS == 0 || V->getType() == RHS->getType()) &&
+ "Invalid shuffle!");
+ unsigned NumElts = cast<VectorType>(V->getType())->getNumElements();
+
+ if (isa<UndefValue>(V)) {
+ Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext())));
+ return V;
+ }
+
+ if (isa<ConstantAggregateZero>(V)) {
+ Mask.assign(NumElts, ConstantInt::get(Type::getInt32Ty(V->getContext()),0));
+ return V;
+ }
+
+ 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) &&
+ EI->getOperand(0)->getType() == V->getType()) {
+ 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) == RHS || RHS == 0) {
+ RHS = EI->getOperand(0);
+ Value *V = CollectShuffleElements(VecOp, Mask, RHS);
+ Mask[InsertedIdx % NumElts] =
+ ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ NumElts+ExtractedIdx);
+ return V;
+ }
+
+ if (VecOp == RHS) {
+ Value *V = CollectShuffleElements(EI->getOperand(0), Mask, RHS);
+ // Update Mask to reflect that `ScalarOp' has been inserted at
+ // position `InsertedIdx' within the vector returned by IEI.
+ Mask[InsertedIdx % NumElts] = Mask[ExtractedIdx];
+
+ // Everything but the extracted element is replaced with the RHS.
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (i != InsertedIdx)
+ Mask[i] = ConstantInt::get(Type::getInt32Ty(V->getContext()),
+ NumElts+i);
+ }
+ return V;
+ }
+
+ // If this insertelement is a chain that comes from exactly these two
+ // vectors, return the vector and the effective shuffle.
+ if (CollectSingleShuffleElements(IEI, EI->getOperand(0), RHS, Mask))
+ return EI->getOperand(0);
+ }
+ }
+ }
+ // TODO: Handle shufflevector here!
+
+ // 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 V;
+}
+
+class CombineVectorInstructions
+ : public BasicBlockPass,
+ public InstVisitor<CombineVectorInstructions, bool> {
+public:
+ static char ID; // Pass identification, replacement for typeid
+ CombineVectorInstructions() : BasicBlockPass(ID) {
+ initializeCombineVectorInstructionsPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnBasicBlock(BasicBlock &B);
+
+ // InstVisitor implementation. Unhandled instructions stay as-is.
+ bool visitInstruction(Instruction &I) { return false; }
+ bool visitInsertElementInst(InsertElementInst &IE);
+};
+
+} // anonymous namespace
+
+char CombineVectorInstructions::ID = 0;
+INITIALIZE_PASS(CombineVectorInstructions, "combine-vector-instructions",
+ "Combine vector instructions", false, false)
+bool CombineVectorInstructions::runOnBasicBlock(BasicBlock &B) {
+ bool Modified = false;
+ for (BasicBlock::iterator BI = B.begin(), BE = B.end(); BI != BE; ++BI)
+ Modified |= visit(&*BI);
+ return Modified;
+}
+
+// TODO(jfb) This function is *almost* as-is from instcombine, avoiding
+// silly cases that should already have been optimized.
+bool CombineVectorInstructions::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) &&
+ EI->getOperand(0)->getType() == IE.getType()) {
+ unsigned NumVectorElts = IE.getType()->getNumElements();
+ unsigned ExtractedIdx =
+ cast<ConstantInt>(EI->getOperand(1))->getZExtValue();
+ unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue();
+
+ if (ExtractedIdx >= NumVectorElts) // Out of range extract.
+ return false;
+
+ if (InsertedIdx >= NumVectorElts) // 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.use_back())) {
+ typedef SmallVector<Constant *, 16> MaskT;
+ MaskT Mask;
+ Value *RHS = 0;
+ Value *LHS = CollectShuffleElements(&IE, Mask, RHS);
+ if (RHS == 0)
+ 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 >= NumVectorElts ? Idx - NumVectorElts : Idx + NumVectorElts;
Derek Schuff 2014/05/12 20:49:22 80 cols
JF 2014/05/12 22:00:01 Done.
+ *I = ConstantInt::get(Type::getInt32Ty(RHS->getContext()), NewIdx);
+ }
+ }
+ IRBuilder<> IRB(&IE);
+ IE.replaceAllUsesWith(
+ IRB.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask)));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+BasicBlockPass *llvm::createCombineVectorInstructionsPass() {
+ return new CombineVectorInstructions();
+}
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | lib/Transforms/NaCl/ExpandShuffleVector.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698