LLVM API Documentation

NVPTXFavorNonGenericAddrSpaces.cpp
Go to the documentation of this file.
00001 //===-- NVPTXFavorNonGenericAddrSpace.cpp - ---------------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // When a load/store accesses the generic address space, checks whether the
00011 // address is casted from a non-generic address space. If so, remove this
00012 // addrspacecast because accessing non-generic address spaces is typically
00013 // faster. Besides seeking addrspacecasts, this optimization also traces into
00014 // the base pointer of a GEP.
00015 //
00016 // For instance, the code below loads a float from an array allocated in
00017 // addrspace(3).
00018 //
00019 // %0 = addrspacecast [10 x float] addrspace(3)* @a to [10 x float]*
00020 // %1 = gep [10 x float]* %0, i64 0, i64 %i
00021 // %2 = load float* %1 ; emits ld.f32
00022 //
00023 // First, function hoistAddrSpaceCastFromGEP reorders the addrspacecast
00024 // and the GEP to expose more optimization opportunities to function
00025 // optimizeMemoryInst. The intermediate code looks like:
00026 //
00027 // %0 = gep [10 x float] addrspace(3)* @a, i64 0, i64 %i
00028 // %1 = addrspacecast float addrspace(3)* %0 to float*
00029 // %2 = load float* %1 ; still emits ld.f32, but will be optimized shortly
00030 //
00031 // Then, function optimizeMemoryInstruction detects a load from addrspacecast'ed
00032 // generic pointers, and folds the load and the addrspacecast into a load from
00033 // the original address space. The final code looks like:
00034 //
00035 // %0 = gep [10 x float] addrspace(3)* @a, i64 0, i64 %i
00036 // %2 = load float addrspace(3)* %0 ; emits ld.shared.f32
00037 //
00038 // This pass may remove an addrspacecast in a different BB. Therefore, we
00039 // implement it as a FunctionPass.
00040 //
00041 //===----------------------------------------------------------------------===//
00042 
00043 #include "NVPTX.h"
00044 #include "llvm/IR/Function.h"
00045 #include "llvm/IR/Instructions.h"
00046 #include "llvm/IR/Operator.h"
00047 #include "llvm/Support/CommandLine.h"
00048 
00049 using namespace llvm;
00050 
00051 // An option to disable this optimization. Enable it by default.
00052 static cl::opt<bool> DisableFavorNonGeneric(
00053   "disable-nvptx-favor-non-generic",
00054   cl::init(false),
00055   cl::desc("Do not convert generic address space usage "
00056            "to non-generic address space usage"),
00057   cl::Hidden);
00058 
00059 namespace {
00060 /// \brief NVPTXFavorNonGenericAddrSpaces
00061 class NVPTXFavorNonGenericAddrSpaces : public FunctionPass {
00062 public:
00063   static char ID;
00064   NVPTXFavorNonGenericAddrSpaces() : FunctionPass(ID) {}
00065 
00066   bool runOnFunction(Function &F) override;
00067 
00068   /// Optimizes load/store instructions. Idx is the index of the pointer operand
00069   /// (0 for load, and 1 for store). Returns true if it changes anything.
00070   bool optimizeMemoryInstruction(Instruction *I, unsigned Idx);
00071   /// Transforms "gep (addrspacecast X), indices" into "addrspacecast (gep X,
00072   /// indices)".  This reordering exposes to optimizeMemoryInstruction more
00073   /// optimization opportunities on loads and stores. Returns true if it changes
00074   /// the program.
00075   bool hoistAddrSpaceCastFromGEP(GEPOperator *GEP);
00076 };
00077 }
00078 
00079 char NVPTXFavorNonGenericAddrSpaces::ID = 0;
00080 
00081 namespace llvm {
00082 void initializeNVPTXFavorNonGenericAddrSpacesPass(PassRegistry &);
00083 }
00084 INITIALIZE_PASS(NVPTXFavorNonGenericAddrSpaces, "nvptx-favor-non-generic",
00085                 "Remove unnecessary non-generic-to-generic addrspacecasts",
00086                 false, false)
00087 
00088 // Decides whether removing Cast is valid and beneficial. Cast can be an
00089 // instruction or a constant expression.
00090 static bool IsEliminableAddrSpaceCast(Operator *Cast) {
00091   // Returns false if not even an addrspacecast.
00092   if (Cast->getOpcode() != Instruction::AddrSpaceCast)
00093     return false;
00094 
00095   Value *Src = Cast->getOperand(0);
00096   PointerType *SrcTy = cast<PointerType>(Src->getType());
00097   PointerType *DestTy = cast<PointerType>(Cast->getType());
00098   // TODO: For now, we only handle the case where the addrspacecast only changes
00099   // the address space but not the type. If the type also changes, we could
00100   // still get rid of the addrspacecast by adding an extra bitcast, but we
00101   // rarely see such scenarios.
00102   if (SrcTy->getElementType() != DestTy->getElementType())
00103     return false;
00104 
00105   // Checks whether the addrspacecast is from a non-generic address space to the
00106   // generic address space.
00107   return (SrcTy->getAddressSpace() != AddressSpace::ADDRESS_SPACE_GENERIC &&
00108           DestTy->getAddressSpace() == AddressSpace::ADDRESS_SPACE_GENERIC);
00109 }
00110 
00111 bool NVPTXFavorNonGenericAddrSpaces::hoistAddrSpaceCastFromGEP(
00112     GEPOperator *GEP) {
00113   Operator *Cast = dyn_cast<Operator>(GEP->getPointerOperand());
00114   if (!Cast)
00115     return false;
00116 
00117   if (!IsEliminableAddrSpaceCast(Cast))
00118     return false;
00119 
00120   SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
00121   if (Instruction *GEPI = dyn_cast<Instruction>(GEP)) {
00122     // %1 = gep (addrspacecast X), indices
00123     // =>
00124     // %0 = gep X, indices
00125     // %1 = addrspacecast %0
00126     GetElementPtrInst *NewGEPI = GetElementPtrInst::Create(Cast->getOperand(0),
00127                                                            Indices,
00128                                                            GEP->getName(),
00129                                                            GEPI);
00130     NewGEPI->setIsInBounds(GEP->isInBounds());
00131     GEP->replaceAllUsesWith(
00132         new AddrSpaceCastInst(NewGEPI, GEP->getType(), "", GEPI));
00133   } else {
00134     // GEP is a constant expression.
00135     Constant *NewGEPCE = ConstantExpr::getGetElementPtr(
00136         cast<Constant>(Cast->getOperand(0)),
00137         Indices,
00138         GEP->isInBounds());
00139     GEP->replaceAllUsesWith(
00140         ConstantExpr::getAddrSpaceCast(NewGEPCE, GEP->getType()));
00141   }
00142 
00143   return true;
00144 }
00145 
00146 bool NVPTXFavorNonGenericAddrSpaces::optimizeMemoryInstruction(Instruction *MI,
00147                                                                unsigned Idx) {
00148   // If the pointer operand is a GEP, hoist the addrspacecast if any from the
00149   // GEP to expose more optimization opportunites.
00150   if (GEPOperator *GEP = dyn_cast<GEPOperator>(MI->getOperand(Idx))) {
00151     hoistAddrSpaceCastFromGEP(GEP);
00152   }
00153 
00154   // load/store (addrspacecast X) => load/store X if shortcutting the
00155   // addrspacecast is valid and can improve performance.
00156   //
00157   // e.g.,
00158   // %1 = addrspacecast float addrspace(3)* %0 to float*
00159   // %2 = load float* %1
00160   // ->
00161   // %2 = load float addrspace(3)* %0
00162   //
00163   // Note: the addrspacecast can also be a constant expression.
00164   if (Operator *Cast = dyn_cast<Operator>(MI->getOperand(Idx))) {
00165     if (IsEliminableAddrSpaceCast(Cast)) {
00166       MI->setOperand(Idx, Cast->getOperand(0));
00167       return true;
00168     }
00169   }
00170 
00171   return false;
00172 }
00173 
00174 bool NVPTXFavorNonGenericAddrSpaces::runOnFunction(Function &F) {
00175   if (DisableFavorNonGeneric)
00176     return false;
00177 
00178   bool Changed = false;
00179   for (Function::iterator B = F.begin(), BE = F.end(); B != BE; ++B) {
00180     for (BasicBlock::iterator I = B->begin(), IE = B->end(); I != IE; ++I) {
00181       if (isa<LoadInst>(I)) {
00182         // V = load P
00183         Changed |= optimizeMemoryInstruction(I, 0);
00184       } else if (isa<StoreInst>(I)) {
00185         // store V, P
00186         Changed |= optimizeMemoryInstruction(I, 1);
00187       }
00188     }
00189   }
00190   return Changed;
00191 }
00192 
00193 FunctionPass *llvm::createNVPTXFavorNonGenericAddrSpacesPass() {
00194   return new NVPTXFavorNonGenericAddrSpaces();
00195 }