1ad04e7adSStanislav Mekhanoshin //===--- AMDGPUPropagateAttributes.cpp --------------------------*- C++ -*-===// 2ad04e7adSStanislav Mekhanoshin // 3ad04e7adSStanislav Mekhanoshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ad04e7adSStanislav Mekhanoshin // See https://llvm.org/LICENSE.txt for license information. 5ad04e7adSStanislav Mekhanoshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ad04e7adSStanislav Mekhanoshin // 7ad04e7adSStanislav Mekhanoshin //===----------------------------------------------------------------------===// 8ad04e7adSStanislav Mekhanoshin // 9ad04e7adSStanislav Mekhanoshin /// \file 10ad04e7adSStanislav Mekhanoshin /// \brief This pass propagates attributes from kernels to the non-entry 11ad04e7adSStanislav Mekhanoshin /// functions. Most of the library functions were not compiled for specific ABI, 12*dc6e8dfdSJacob Lambert /// yet will be correctly compiled if proper attributes are propagated from the 13ad04e7adSStanislav Mekhanoshin /// caller. 14ad04e7adSStanislav Mekhanoshin /// 15ad04e7adSStanislav Mekhanoshin /// The pass analyzes call graph and propagates ABI target features through the 16ad04e7adSStanislav Mekhanoshin /// call graph. 17ad04e7adSStanislav Mekhanoshin /// 18ad04e7adSStanislav Mekhanoshin /// It can run in two modes: as a function or module pass. A function pass 19ad04e7adSStanislav Mekhanoshin /// simply propagates attributes. A module pass clones functions if there are 20*dc6e8dfdSJacob Lambert /// callers with different ABI. If a function is cloned all call sites will 21ad04e7adSStanislav Mekhanoshin /// be updated to use a correct clone. 22ad04e7adSStanislav Mekhanoshin /// 23ad04e7adSStanislav Mekhanoshin /// A function pass is limited in functionality but can run early in the 24ad04e7adSStanislav Mekhanoshin /// pipeline. A module pass is more powerful but has to run late, so misses 25ad04e7adSStanislav Mekhanoshin /// library folding opportunities. 26ad04e7adSStanislav Mekhanoshin // 27ad04e7adSStanislav Mekhanoshin //===----------------------------------------------------------------------===// 28ad04e7adSStanislav Mekhanoshin 29ad04e7adSStanislav Mekhanoshin #include "AMDGPU.h" 30560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 31560d7e04Sdfukalov #include "Utils/AMDGPUBaseInfo.h" 32ad04e7adSStanislav Mekhanoshin #include "llvm/ADT/SmallSet.h" 3353c43431SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h" 34560d7e04Sdfukalov #include "llvm/CodeGen/TargetSubtargetInfo.h" 35560d7e04Sdfukalov #include "llvm/IR/InstrTypes.h" 36ad04e7adSStanislav Mekhanoshin #include "llvm/Target/TargetMachine.h" 37ad04e7adSStanislav Mekhanoshin #include "llvm/Transforms/Utils/Cloning.h" 38560d7e04Sdfukalov 395e643036SMatt Arsenault #define DEBUG_TYPE "amdgpu-propagate-attributes" 405e643036SMatt Arsenault 41ad04e7adSStanislav Mekhanoshin using namespace llvm; 42ad04e7adSStanislav Mekhanoshin 43ad04e7adSStanislav Mekhanoshin namespace llvm { 44ad04e7adSStanislav Mekhanoshin extern const SubtargetFeatureKV AMDGPUFeatureKV[AMDGPU::NumSubtargetFeatures-1]; 45ad04e7adSStanislav Mekhanoshin } 46ad04e7adSStanislav Mekhanoshin 47ad04e7adSStanislav Mekhanoshin namespace { 48ad04e7adSStanislav Mekhanoshin 494c4b7184SStanislav Mekhanoshin // Target features to propagate. 504c4b7184SStanislav Mekhanoshin static constexpr const FeatureBitset TargetFeatures = { 51ad04e7adSStanislav Mekhanoshin AMDGPU::FeatureWavefrontSize16, 52ad04e7adSStanislav Mekhanoshin AMDGPU::FeatureWavefrontSize32, 53ad04e7adSStanislav Mekhanoshin AMDGPU::FeatureWavefrontSize64 54ad04e7adSStanislav Mekhanoshin }; 55ad04e7adSStanislav Mekhanoshin 564c4b7184SStanislav Mekhanoshin // Attributes to propagate. 5753c43431SMatt Arsenault // TODO: Support conservative min/max merging instead of cloning. 584c4b7184SStanislav Mekhanoshin static constexpr const char* AttributeNames[] = { 5953c43431SMatt Arsenault "amdgpu-waves-per-eu", 6053c43431SMatt Arsenault "amdgpu-flat-work-group-size" 614c4b7184SStanislav Mekhanoshin }; 624c4b7184SStanislav Mekhanoshin 634c4b7184SStanislav Mekhanoshin static constexpr unsigned NumAttr = 644c4b7184SStanislav Mekhanoshin sizeof(AttributeNames) / sizeof(AttributeNames[0]); 654c4b7184SStanislav Mekhanoshin 664c4b7184SStanislav Mekhanoshin class AMDGPUPropagateAttributes { 674c4b7184SStanislav Mekhanoshin 684c4b7184SStanislav Mekhanoshin class FnProperties { 694c4b7184SStanislav Mekhanoshin private: 704c4b7184SStanislav Mekhanoshin explicit FnProperties(const FeatureBitset &&FB) : Features(FB) {} 714c4b7184SStanislav Mekhanoshin 724c4b7184SStanislav Mekhanoshin public: 734c4b7184SStanislav Mekhanoshin explicit FnProperties(const TargetMachine &TM, const Function &F) { 744c4b7184SStanislav Mekhanoshin Features = TM.getSubtargetImpl(F)->getFeatureBits(); 754c4b7184SStanislav Mekhanoshin 764c4b7184SStanislav Mekhanoshin for (unsigned I = 0; I < NumAttr; ++I) 774c4b7184SStanislav Mekhanoshin if (F.hasFnAttribute(AttributeNames[I])) 784c4b7184SStanislav Mekhanoshin Attributes[I] = F.getFnAttribute(AttributeNames[I]); 794c4b7184SStanislav Mekhanoshin } 804c4b7184SStanislav Mekhanoshin 814c4b7184SStanislav Mekhanoshin bool operator == (const FnProperties &Other) const { 824c4b7184SStanislav Mekhanoshin if ((Features & TargetFeatures) != (Other.Features & TargetFeatures)) 834c4b7184SStanislav Mekhanoshin return false; 844c4b7184SStanislav Mekhanoshin for (unsigned I = 0; I < NumAttr; ++I) 854c4b7184SStanislav Mekhanoshin if (Attributes[I] != Other.Attributes[I]) 864c4b7184SStanislav Mekhanoshin return false; 874c4b7184SStanislav Mekhanoshin return true; 884c4b7184SStanislav Mekhanoshin } 894c4b7184SStanislav Mekhanoshin 904c4b7184SStanislav Mekhanoshin FnProperties adjustToCaller(const FnProperties &CallerProps) const { 914c4b7184SStanislav Mekhanoshin FnProperties New((Features & ~TargetFeatures) | CallerProps.Features); 924c4b7184SStanislav Mekhanoshin for (unsigned I = 0; I < NumAttr; ++I) 934c4b7184SStanislav Mekhanoshin New.Attributes[I] = CallerProps.Attributes[I]; 944c4b7184SStanislav Mekhanoshin return New; 954c4b7184SStanislav Mekhanoshin } 964c4b7184SStanislav Mekhanoshin 974c4b7184SStanislav Mekhanoshin FeatureBitset Features; 984c4b7184SStanislav Mekhanoshin Optional<Attribute> Attributes[NumAttr]; 994c4b7184SStanislav Mekhanoshin }; 1004c4b7184SStanislav Mekhanoshin 101ad04e7adSStanislav Mekhanoshin class Clone { 102ad04e7adSStanislav Mekhanoshin public: 1034c4b7184SStanislav Mekhanoshin Clone(const FnProperties &Props, Function *OrigF, Function *NewF) : 1044c4b7184SStanislav Mekhanoshin Properties(Props), OrigF(OrigF), NewF(NewF) {} 105ad04e7adSStanislav Mekhanoshin 1064c4b7184SStanislav Mekhanoshin FnProperties Properties; 107ad04e7adSStanislav Mekhanoshin Function *OrigF; 108ad04e7adSStanislav Mekhanoshin Function *NewF; 109ad04e7adSStanislav Mekhanoshin }; 110ad04e7adSStanislav Mekhanoshin 111ad04e7adSStanislav Mekhanoshin const TargetMachine *TM; 112ad04e7adSStanislav Mekhanoshin 113ad04e7adSStanislav Mekhanoshin // Clone functions as needed or just set attributes. 114ad04e7adSStanislav Mekhanoshin bool AllowClone; 115ad04e7adSStanislav Mekhanoshin 116ad04e7adSStanislav Mekhanoshin // Option propagation roots. 117ad04e7adSStanislav Mekhanoshin SmallSet<Function *, 32> Roots; 118ad04e7adSStanislav Mekhanoshin 119ad04e7adSStanislav Mekhanoshin // Clones of functions with their attributes. 120ad04e7adSStanislav Mekhanoshin SmallVector<Clone, 32> Clones; 121ad04e7adSStanislav Mekhanoshin 122ad04e7adSStanislav Mekhanoshin // Find a clone with required features. 1234c4b7184SStanislav Mekhanoshin Function *findFunction(const FnProperties &PropsNeeded, 124ad04e7adSStanislav Mekhanoshin Function *OrigF); 125ad04e7adSStanislav Mekhanoshin 1264c4b7184SStanislav Mekhanoshin // Clone function \p F and set \p NewProps on the clone. 127ad04e7adSStanislav Mekhanoshin // Cole takes the name of original function. 1284c4b7184SStanislav Mekhanoshin Function *cloneWithProperties(Function &F, const FnProperties &NewProps); 129ad04e7adSStanislav Mekhanoshin 130ad04e7adSStanislav Mekhanoshin // Set new function's features in place. 131ad04e7adSStanislav Mekhanoshin void setFeatures(Function &F, const FeatureBitset &NewFeatures); 132ad04e7adSStanislav Mekhanoshin 1334c4b7184SStanislav Mekhanoshin // Set new function's attributes in place. 1344c4b7184SStanislav Mekhanoshin void setAttributes(Function &F, const ArrayRef<Optional<Attribute>> NewAttrs); 1354c4b7184SStanislav Mekhanoshin 136ad04e7adSStanislav Mekhanoshin std::string getFeatureString(const FeatureBitset &Features) const; 137ad04e7adSStanislav Mekhanoshin 138ad04e7adSStanislav Mekhanoshin // Propagate attributes from Roots. 139ad04e7adSStanislav Mekhanoshin bool process(); 140ad04e7adSStanislav Mekhanoshin 141ad04e7adSStanislav Mekhanoshin public: 142660cae84SJon Chesterfield AMDGPUPropagateAttributes(const TargetMachine *TM, bool AllowClone) : 143660cae84SJon Chesterfield TM(TM), AllowClone(AllowClone) {} 144ad04e7adSStanislav Mekhanoshin 145ad04e7adSStanislav Mekhanoshin // Use F as a root and propagate its attributes. 146ad04e7adSStanislav Mekhanoshin bool process(Function &F); 147ad04e7adSStanislav Mekhanoshin 148ad04e7adSStanislav Mekhanoshin // Propagate attributes starting from kernel functions. 149660cae84SJon Chesterfield bool process(Module &M); 150ad04e7adSStanislav Mekhanoshin }; 151ad04e7adSStanislav Mekhanoshin 152*dc6e8dfdSJacob Lambert // Allows to propagate attributes early, but no cloning is allowed as it must 153ad04e7adSStanislav Mekhanoshin // be a function pass to run before any optimizations. 154ad04e7adSStanislav Mekhanoshin // TODO: We shall only need a one instance of module pass, but that needs to be 155ad04e7adSStanislav Mekhanoshin // in the linker pipeline which is currently not possible. 156ad04e7adSStanislav Mekhanoshin class AMDGPUPropagateAttributesEarly : public FunctionPass { 157ad04e7adSStanislav Mekhanoshin const TargetMachine *TM; 158ad04e7adSStanislav Mekhanoshin 159ad04e7adSStanislav Mekhanoshin public: 160ad04e7adSStanislav Mekhanoshin static char ID; // Pass identification 161ad04e7adSStanislav Mekhanoshin 162ad04e7adSStanislav Mekhanoshin AMDGPUPropagateAttributesEarly(const TargetMachine *TM = nullptr) : 163ad04e7adSStanislav Mekhanoshin FunctionPass(ID), TM(TM) { 164ad04e7adSStanislav Mekhanoshin initializeAMDGPUPropagateAttributesEarlyPass( 165ad04e7adSStanislav Mekhanoshin *PassRegistry::getPassRegistry()); 166ad04e7adSStanislav Mekhanoshin } 167ad04e7adSStanislav Mekhanoshin 168ad04e7adSStanislav Mekhanoshin bool runOnFunction(Function &F) override; 169ad04e7adSStanislav Mekhanoshin }; 170ad04e7adSStanislav Mekhanoshin 171*dc6e8dfdSJacob Lambert // Allows to propagate attributes with cloning but does that late in the 172ad04e7adSStanislav Mekhanoshin // pipeline. 173ad04e7adSStanislav Mekhanoshin class AMDGPUPropagateAttributesLate : public ModulePass { 174ad04e7adSStanislav Mekhanoshin const TargetMachine *TM; 175ad04e7adSStanislav Mekhanoshin 176ad04e7adSStanislav Mekhanoshin public: 177ad04e7adSStanislav Mekhanoshin static char ID; // Pass identification 178ad04e7adSStanislav Mekhanoshin 179ad04e7adSStanislav Mekhanoshin AMDGPUPropagateAttributesLate(const TargetMachine *TM = nullptr) : 180ad04e7adSStanislav Mekhanoshin ModulePass(ID), TM(TM) { 181ad04e7adSStanislav Mekhanoshin initializeAMDGPUPropagateAttributesLatePass( 182ad04e7adSStanislav Mekhanoshin *PassRegistry::getPassRegistry()); 183ad04e7adSStanislav Mekhanoshin } 184ad04e7adSStanislav Mekhanoshin 185ad04e7adSStanislav Mekhanoshin bool runOnModule(Module &M) override; 186ad04e7adSStanislav Mekhanoshin }; 187ad04e7adSStanislav Mekhanoshin 188ad04e7adSStanislav Mekhanoshin } // end anonymous namespace. 189ad04e7adSStanislav Mekhanoshin 190ad04e7adSStanislav Mekhanoshin char AMDGPUPropagateAttributesEarly::ID = 0; 191ad04e7adSStanislav Mekhanoshin char AMDGPUPropagateAttributesLate::ID = 0; 192ad04e7adSStanislav Mekhanoshin 193ad04e7adSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUPropagateAttributesEarly, 194ad04e7adSStanislav Mekhanoshin "amdgpu-propagate-attributes-early", 195ad04e7adSStanislav Mekhanoshin "Early propagate attributes from kernels to functions", 196ad04e7adSStanislav Mekhanoshin false, false) 197ad04e7adSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUPropagateAttributesLate, 198ad04e7adSStanislav Mekhanoshin "amdgpu-propagate-attributes-late", 199ad04e7adSStanislav Mekhanoshin "Late propagate attributes from kernels to functions", 200ad04e7adSStanislav Mekhanoshin false, false) 201ad04e7adSStanislav Mekhanoshin 202ad04e7adSStanislav Mekhanoshin Function * 2034c4b7184SStanislav Mekhanoshin AMDGPUPropagateAttributes::findFunction(const FnProperties &PropsNeeded, 204ad04e7adSStanislav Mekhanoshin Function *OrigF) { 205ad04e7adSStanislav Mekhanoshin // TODO: search for clone's clones. 206ad04e7adSStanislav Mekhanoshin for (Clone &C : Clones) 2074c4b7184SStanislav Mekhanoshin if (C.OrigF == OrigF && PropsNeeded == C.Properties) 208ad04e7adSStanislav Mekhanoshin return C.NewF; 209ad04e7adSStanislav Mekhanoshin 210ad04e7adSStanislav Mekhanoshin return nullptr; 211ad04e7adSStanislav Mekhanoshin } 212ad04e7adSStanislav Mekhanoshin 213660cae84SJon Chesterfield bool AMDGPUPropagateAttributes::process(Module &M) { 214ad04e7adSStanislav Mekhanoshin for (auto &F : M.functions()) 215ad04e7adSStanislav Mekhanoshin if (AMDGPU::isEntryFunctionCC(F.getCallingConv())) 216ad04e7adSStanislav Mekhanoshin Roots.insert(&F); 217ad04e7adSStanislav Mekhanoshin 218ad04e7adSStanislav Mekhanoshin return process(); 219ad04e7adSStanislav Mekhanoshin } 220ad04e7adSStanislav Mekhanoshin 221ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributes::process(Function &F) { 222ad04e7adSStanislav Mekhanoshin Roots.insert(&F); 223ad04e7adSStanislav Mekhanoshin return process(); 224ad04e7adSStanislav Mekhanoshin } 225ad04e7adSStanislav Mekhanoshin 226ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributes::process() { 227ad04e7adSStanislav Mekhanoshin bool Changed = false; 228ad04e7adSStanislav Mekhanoshin SmallSet<Function *, 32> NewRoots; 229ad04e7adSStanislav Mekhanoshin SmallSet<Function *, 32> Replaced; 230ad04e7adSStanislav Mekhanoshin 231ad04e7adSStanislav Mekhanoshin if (Roots.empty()) 232ad04e7adSStanislav Mekhanoshin return false; 233ad04e7adSStanislav Mekhanoshin Module &M = *(*Roots.begin())->getParent(); 234ad04e7adSStanislav Mekhanoshin 235ad04e7adSStanislav Mekhanoshin do { 236ad04e7adSStanislav Mekhanoshin Roots.insert(NewRoots.begin(), NewRoots.end()); 237ad04e7adSStanislav Mekhanoshin NewRoots.clear(); 238ad04e7adSStanislav Mekhanoshin 239ad04e7adSStanislav Mekhanoshin for (auto &F : M.functions()) { 240e06d707aSStanislav Mekhanoshin if (F.isDeclaration()) 241ad04e7adSStanislav Mekhanoshin continue; 242ad04e7adSStanislav Mekhanoshin 2434c4b7184SStanislav Mekhanoshin const FnProperties CalleeProps(*TM, F); 244ad04e7adSStanislav Mekhanoshin SmallVector<std::pair<CallBase *, Function *>, 32> ToReplace; 245e06d707aSStanislav Mekhanoshin SmallSet<CallBase *, 32> Visited; 246ad04e7adSStanislav Mekhanoshin 247ad04e7adSStanislav Mekhanoshin for (User *U : F.users()) { 248ad04e7adSStanislav Mekhanoshin Instruction *I = dyn_cast<Instruction>(U); 249ad04e7adSStanislav Mekhanoshin if (!I) 250ad04e7adSStanislav Mekhanoshin continue; 251ad04e7adSStanislav Mekhanoshin CallBase *CI = dyn_cast<CallBase>(I); 252fcd32d62Sjweightma // Only propagate attributes if F is the called function. Specifically, 253fcd32d62Sjweightma // do not propagate attributes if F is passed as an argument. 254fcd32d62Sjweightma // FIXME: handle bitcasted callee, e.g. 255fcd32d62Sjweightma // %retval = call i8* bitcast (i32* ()* @f to i8* ()*)() 256fcd32d62Sjweightma if (!CI || CI->getCalledOperand() != &F) 257ad04e7adSStanislav Mekhanoshin continue; 258ad04e7adSStanislav Mekhanoshin Function *Caller = CI->getCaller(); 259e06d707aSStanislav Mekhanoshin if (!Caller || !Visited.insert(CI).second) 260ad04e7adSStanislav Mekhanoshin continue; 261e06d707aSStanislav Mekhanoshin if (!Roots.count(Caller) && !NewRoots.count(Caller)) 262ad04e7adSStanislav Mekhanoshin continue; 263ad04e7adSStanislav Mekhanoshin 2644c4b7184SStanislav Mekhanoshin const FnProperties CallerProps(*TM, *Caller); 265ad04e7adSStanislav Mekhanoshin 2662cdb34efSKonstantin Zhuravlyov if (CalleeProps == CallerProps) { 267e06d707aSStanislav Mekhanoshin if (!Roots.count(&F)) 268ad04e7adSStanislav Mekhanoshin NewRoots.insert(&F); 269ad04e7adSStanislav Mekhanoshin continue; 270ad04e7adSStanislav Mekhanoshin } 271ad04e7adSStanislav Mekhanoshin 2724c4b7184SStanislav Mekhanoshin Function *NewF = findFunction(CallerProps, &F); 273ad04e7adSStanislav Mekhanoshin if (!NewF) { 2744c4b7184SStanislav Mekhanoshin const FnProperties NewProps = CalleeProps.adjustToCaller(CallerProps); 275ad04e7adSStanislav Mekhanoshin if (!AllowClone) { 276*dc6e8dfdSJacob Lambert // This may set different features on different iterations if 277ad04e7adSStanislav Mekhanoshin // there is a contradiction in callers' attributes. In this case 278ad04e7adSStanislav Mekhanoshin // we rely on a second pass running on Module, which is allowed 279ad04e7adSStanislav Mekhanoshin // to clone. 2804c4b7184SStanislav Mekhanoshin setFeatures(F, NewProps.Features); 2814c4b7184SStanislav Mekhanoshin setAttributes(F, NewProps.Attributes); 282ad04e7adSStanislav Mekhanoshin NewRoots.insert(&F); 283ad04e7adSStanislav Mekhanoshin Changed = true; 284ad04e7adSStanislav Mekhanoshin break; 285ad04e7adSStanislav Mekhanoshin } 286ad04e7adSStanislav Mekhanoshin 2874c4b7184SStanislav Mekhanoshin NewF = cloneWithProperties(F, NewProps); 2884c4b7184SStanislav Mekhanoshin Clones.push_back(Clone(CallerProps, &F, NewF)); 289ad04e7adSStanislav Mekhanoshin NewRoots.insert(NewF); 290ad04e7adSStanislav Mekhanoshin } 291ad04e7adSStanislav Mekhanoshin 292ad04e7adSStanislav Mekhanoshin ToReplace.push_back(std::make_pair(CI, NewF)); 293ad04e7adSStanislav Mekhanoshin Replaced.insert(&F); 294ad04e7adSStanislav Mekhanoshin 295ad04e7adSStanislav Mekhanoshin Changed = true; 296ad04e7adSStanislav Mekhanoshin } 297ad04e7adSStanislav Mekhanoshin 298ad04e7adSStanislav Mekhanoshin while (!ToReplace.empty()) { 299ad04e7adSStanislav Mekhanoshin auto R = ToReplace.pop_back_val(); 300ad04e7adSStanislav Mekhanoshin R.first->setCalledFunction(R.second); 301ad04e7adSStanislav Mekhanoshin } 302ad04e7adSStanislav Mekhanoshin } 303ad04e7adSStanislav Mekhanoshin } while (!NewRoots.empty()); 304ad04e7adSStanislav Mekhanoshin 305ad04e7adSStanislav Mekhanoshin for (Function *F : Replaced) { 306ad04e7adSStanislav Mekhanoshin if (F->use_empty()) 307ad04e7adSStanislav Mekhanoshin F->eraseFromParent(); 308ad04e7adSStanislav Mekhanoshin } 309ad04e7adSStanislav Mekhanoshin 310e06d707aSStanislav Mekhanoshin Roots.clear(); 311e06d707aSStanislav Mekhanoshin Clones.clear(); 312e06d707aSStanislav Mekhanoshin 313ad04e7adSStanislav Mekhanoshin return Changed; 314ad04e7adSStanislav Mekhanoshin } 315ad04e7adSStanislav Mekhanoshin 316ad04e7adSStanislav Mekhanoshin Function * 3174c4b7184SStanislav Mekhanoshin AMDGPUPropagateAttributes::cloneWithProperties(Function &F, 3184c4b7184SStanislav Mekhanoshin const FnProperties &NewProps) { 319ad04e7adSStanislav Mekhanoshin LLVM_DEBUG(dbgs() << "Cloning " << F.getName() << '\n'); 320ad04e7adSStanislav Mekhanoshin 321ad04e7adSStanislav Mekhanoshin ValueToValueMapTy dummy; 322ad04e7adSStanislav Mekhanoshin Function *NewF = CloneFunction(&F, dummy); 3234c4b7184SStanislav Mekhanoshin setFeatures(*NewF, NewProps.Features); 3244c4b7184SStanislav Mekhanoshin setAttributes(*NewF, NewProps.Attributes); 3256e00e3fcSStanislav Mekhanoshin NewF->setVisibility(GlobalValue::DefaultVisibility); 3266e00e3fcSStanislav Mekhanoshin NewF->setLinkage(GlobalValue::InternalLinkage); 327ad04e7adSStanislav Mekhanoshin 328ad04e7adSStanislav Mekhanoshin // Swap names. If that is the only clone it will retain the name of now 3296e00e3fcSStanislav Mekhanoshin // dead value. Preserve original name for externally visible functions. 3306e00e3fcSStanislav Mekhanoshin if (F.hasName() && F.hasLocalLinkage()) { 331adcd0268SBenjamin Kramer std::string NewName = std::string(NewF->getName()); 332ad04e7adSStanislav Mekhanoshin NewF->takeName(&F); 333ad04e7adSStanislav Mekhanoshin F.setName(NewName); 334ad04e7adSStanislav Mekhanoshin } 335ad04e7adSStanislav Mekhanoshin 336ad04e7adSStanislav Mekhanoshin return NewF; 337ad04e7adSStanislav Mekhanoshin } 338ad04e7adSStanislav Mekhanoshin 339ad04e7adSStanislav Mekhanoshin void AMDGPUPropagateAttributes::setFeatures(Function &F, 340ad04e7adSStanislav Mekhanoshin const FeatureBitset &NewFeatures) { 341ad04e7adSStanislav Mekhanoshin std::string NewFeatureStr = getFeatureString(NewFeatures); 342ad04e7adSStanislav Mekhanoshin 343ad04e7adSStanislav Mekhanoshin LLVM_DEBUG(dbgs() << "Set features " 344ad04e7adSStanislav Mekhanoshin << getFeatureString(NewFeatures & TargetFeatures) 345ad04e7adSStanislav Mekhanoshin << " on " << F.getName() << '\n'); 346ad04e7adSStanislav Mekhanoshin 347ad04e7adSStanislav Mekhanoshin F.removeFnAttr("target-features"); 348ad04e7adSStanislav Mekhanoshin F.addFnAttr("target-features", NewFeatureStr); 349ad04e7adSStanislav Mekhanoshin } 350ad04e7adSStanislav Mekhanoshin 3514c4b7184SStanislav Mekhanoshin void AMDGPUPropagateAttributes::setAttributes(Function &F, 3524c4b7184SStanislav Mekhanoshin const ArrayRef<Optional<Attribute>> NewAttrs) { 3534c4b7184SStanislav Mekhanoshin LLVM_DEBUG(dbgs() << "Set attributes on " << F.getName() << ":\n"); 3544c4b7184SStanislav Mekhanoshin for (unsigned I = 0; I < NumAttr; ++I) { 3554c4b7184SStanislav Mekhanoshin F.removeFnAttr(AttributeNames[I]); 3564c4b7184SStanislav Mekhanoshin if (NewAttrs[I]) { 3574c4b7184SStanislav Mekhanoshin LLVM_DEBUG(dbgs() << '\t' << NewAttrs[I]->getAsString() << '\n'); 3584c4b7184SStanislav Mekhanoshin F.addFnAttr(*NewAttrs[I]); 3594c4b7184SStanislav Mekhanoshin } 3604c4b7184SStanislav Mekhanoshin } 3614c4b7184SStanislav Mekhanoshin } 3624c4b7184SStanislav Mekhanoshin 363ad04e7adSStanislav Mekhanoshin std::string 364ad04e7adSStanislav Mekhanoshin AMDGPUPropagateAttributes::getFeatureString(const FeatureBitset &Features) const 365ad04e7adSStanislav Mekhanoshin { 366ad04e7adSStanislav Mekhanoshin std::string Ret; 367ad04e7adSStanislav Mekhanoshin for (const SubtargetFeatureKV &KV : AMDGPUFeatureKV) { 368ad04e7adSStanislav Mekhanoshin if (Features[KV.Value]) 369ad04e7adSStanislav Mekhanoshin Ret += (StringRef("+") + KV.Key + ",").str(); 370ad04e7adSStanislav Mekhanoshin else if (TargetFeatures[KV.Value]) 371ad04e7adSStanislav Mekhanoshin Ret += (StringRef("-") + KV.Key + ",").str(); 372ad04e7adSStanislav Mekhanoshin } 373ad04e7adSStanislav Mekhanoshin Ret.pop_back(); // Remove last comma. 374ad04e7adSStanislav Mekhanoshin return Ret; 375ad04e7adSStanislav Mekhanoshin } 376ad04e7adSStanislav Mekhanoshin 377ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributesEarly::runOnFunction(Function &F) { 37853c43431SMatt Arsenault if (!TM) { 37953c43431SMatt Arsenault auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 38053c43431SMatt Arsenault if (!TPC) 38153c43431SMatt Arsenault return false; 38253c43431SMatt Arsenault 38353c43431SMatt Arsenault TM = &TPC->getTM<TargetMachine>(); 38453c43431SMatt Arsenault } 38553c43431SMatt Arsenault 38653c43431SMatt Arsenault if (!AMDGPU::isEntryFunctionCC(F.getCallingConv())) 387ad04e7adSStanislav Mekhanoshin return false; 388ad04e7adSStanislav Mekhanoshin 389ad04e7adSStanislav Mekhanoshin return AMDGPUPropagateAttributes(TM, false).process(F); 390ad04e7adSStanislav Mekhanoshin } 391ad04e7adSStanislav Mekhanoshin 392ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributesLate::runOnModule(Module &M) { 39353c43431SMatt Arsenault if (!TM) { 39453c43431SMatt Arsenault auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 39553c43431SMatt Arsenault if (!TPC) 396ad04e7adSStanislav Mekhanoshin return false; 397ad04e7adSStanislav Mekhanoshin 39853c43431SMatt Arsenault TM = &TPC->getTM<TargetMachine>(); 39953c43431SMatt Arsenault } 400660cae84SJon Chesterfield 401660cae84SJon Chesterfield return AMDGPUPropagateAttributes(TM, true).process(M); 402ad04e7adSStanislav Mekhanoshin } 403ad04e7adSStanislav Mekhanoshin 404ad04e7adSStanislav Mekhanoshin FunctionPass 405ad04e7adSStanislav Mekhanoshin *llvm::createAMDGPUPropagateAttributesEarlyPass(const TargetMachine *TM) { 406ad04e7adSStanislav Mekhanoshin return new AMDGPUPropagateAttributesEarly(TM); 407ad04e7adSStanislav Mekhanoshin } 408ad04e7adSStanislav Mekhanoshin 409ad04e7adSStanislav Mekhanoshin ModulePass 410ad04e7adSStanislav Mekhanoshin *llvm::createAMDGPUPropagateAttributesLatePass(const TargetMachine *TM) { 411ad04e7adSStanislav Mekhanoshin return new AMDGPUPropagateAttributesLate(TM); 412ad04e7adSStanislav Mekhanoshin } 413a5f863e0SArthur Eubanks 414a5f863e0SArthur Eubanks PreservedAnalyses 415a5f863e0SArthur Eubanks AMDGPUPropagateAttributesEarlyPass::run(Function &F, 416a5f863e0SArthur Eubanks FunctionAnalysisManager &AM) { 417a5f863e0SArthur Eubanks if (!AMDGPU::isEntryFunctionCC(F.getCallingConv())) 418a5f863e0SArthur Eubanks return PreservedAnalyses::all(); 419a5f863e0SArthur Eubanks 420a5f863e0SArthur Eubanks return AMDGPUPropagateAttributes(&TM, false).process(F) 421a5f863e0SArthur Eubanks ? PreservedAnalyses::none() 422a5f863e0SArthur Eubanks : PreservedAnalyses::all(); 423a5f863e0SArthur Eubanks } 424a5f863e0SArthur Eubanks 425a5f863e0SArthur Eubanks PreservedAnalyses 426660cae84SJon Chesterfield AMDGPUPropagateAttributesLatePass::run(Module &M, ModuleAnalysisManager &AM) { 427660cae84SJon Chesterfield return AMDGPUPropagateAttributes(&TM, true).process(M) 428660cae84SJon Chesterfield ? PreservedAnalyses::none() 429660cae84SJon Chesterfield : PreservedAnalyses::all(); 430a5f863e0SArthur Eubanks } 431