blob: de985233653994f41cc7b8c62c2a13645af2d584 [file] [log] [blame] [edit]
//===- 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/Analysis/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<TargetLibraryInfoWrapperPass>();
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 = &F.getParent()->getDataLayout();
TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
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();
}