LLVM API Documentation
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 }