Index: lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp =================================================================== --- lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp +++ lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp @@ -63,16 +63,20 @@ static char ID; NVPTXFavorNonGenericAddrSpaces() : FunctionPass(ID) {} + bool doInitialization(Module &M) override; bool runOnFunction(Function &F) override; /// Optimizes load/store instructions. Idx is the index of the pointer operand /// (0 for load, and 1 for store). Returns true if it changes anything. bool optimizeMemoryInstruction(Instruction *I, unsigned Idx); /// Transforms "gep (addrspacecast X), indices" into "addrspacecast (gep X, - /// indices)". This reordering exposes to optimizeMemoryInstruction more + /// indices)". This reordering exposes to optimizeMemoryInstruction more /// optimization opportunities on loads and stores. Returns true if it changes /// the program. bool hoistAddrSpaceCastFromGEP(GEPOperator *GEP); + /// Run hoistAddrSpaceCastFromGEP on all the recursive elements of + /// \c Initializer. + bool canonicalizeInitializer(Constant *Initializer); }; } @@ -143,10 +147,11 @@ bool NVPTXFavorNonGenericAddrSpaces::optimizeMemoryInstruction(Instruction *MI, unsigned Idx) { + bool Changed = false; // If the pointer operand is a GEP, hoist the addrspacecast if any from the // GEP to expose more optimization opportunites. if (GEPOperator *GEP = dyn_cast(MI->getOperand(Idx))) { - hoistAddrSpaceCastFromGEP(GEP); + Changed |= hoistAddrSpaceCastFromGEP(GEP); } // load/store (addrspacecast X) => load/store X if shortcutting the @@ -162,10 +167,41 @@ if (Operator *Cast = dyn_cast(MI->getOperand(Idx))) { if (IsEliminableAddrSpaceCast(Cast)) { MI->setOperand(Idx, Cast->getOperand(0)); - return true; + Changed = true; } } + return Changed; +} +bool NVPTXFavorNonGenericAddrSpaces::doInitialization(Module &M) { + bool Changed = false; + // Canonicalizes all global variable initializers to hoist addrspacecast to + // the outermost possible level. This enables NVPTXAsmPrinter to correctly + // print more global variables. + for (auto &GV : M.globals()) { + if (GV.hasInitializer()) + Changed |= canonicalizeInitializer(GV.getInitializer()); + } + return Changed; +} + +bool NVPTXFavorNonGenericAddrSpaces::canonicalizeInitializer(Constant * + Initializer) { + if (GEPOperator *GEP = dyn_cast(Initializer)) { + return hoistAddrSpaceCastFromGEP(GEP); + } + + bool Changed = false; + if (Initializer->getType()->isStructTy() || + Initializer->getType()->isArrayTy() || + Initializer->getType()->isVectorTy()) { + // Trace into the elements of Initializer if it is a struct, array, or + // vector. + for (unsigned I = 0; I != Initializer->getNumOperands(); ++I) { + Changed |= + canonicalizeInitializer(cast(Initializer->getOperand(I))); + } + } return false; } Index: test/CodeGen/NVPTX/addrspacecast-gvar.ll =================================================================== --- test/CodeGen/NVPTX/addrspacecast-gvar.ll +++ test/CodeGen/NVPTX/addrspacecast-gvar.ll @@ -5,9 +5,11 @@ ; CHECK: .visible .global .align 4 .u32 g3 = g; ; CHECK: .visible .global .align 8 .u32 g4[2] = {0, generic(g)}; ; CHECK: .visible .global .align 8 .u32 g5[2] = {0, generic(g+8)}; +; CHECK: .visible .global .align 8 .u32 g6[2] = {0, generic(g+8)}; @g = addrspace(1) global i32 42 @g2 = addrspace(1) global i32* addrspacecast (i32 addrspace(1)* @g to i32*) @g3 = addrspace(1) global i32 addrspace(1)* @g @g4 = constant {i32*, i32*} {i32* null, i32* addrspacecast (i32 addrspace(1)* @g to i32*)} @g5 = constant {i32*, i32*} {i32* null, i32* addrspacecast (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* @g, i32 2) to i32*)} +@g6 = constant {i32*, i32*} {i32* null, i32* getelementptr (i32, i32* addrspacecast (i32 addrspace(1)* @g to i32*), i32 2)}