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,
12dc6e8dfdSJacob 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
20dc6e8dfdSJacob 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.
58*ec57b375SMatt Arsenault static constexpr const char *AttributeNames[] = {"amdgpu-waves-per-eu"};
594c4b7184SStanislav Mekhanoshin 
604c4b7184SStanislav Mekhanoshin static constexpr unsigned NumAttr =
614c4b7184SStanislav Mekhanoshin   sizeof(AttributeNames) / sizeof(AttributeNames[0]);
624c4b7184SStanislav Mekhanoshin 
634c4b7184SStanislav Mekhanoshin class AMDGPUPropagateAttributes {
644c4b7184SStanislav Mekhanoshin 
654c4b7184SStanislav Mekhanoshin   class FnProperties {
664c4b7184SStanislav Mekhanoshin   private:
FnProperties(const FeatureBitset && FB)674c4b7184SStanislav Mekhanoshin     explicit FnProperties(const FeatureBitset &&FB) : Features(FB) {}
684c4b7184SStanislav Mekhanoshin 
694c4b7184SStanislav Mekhanoshin   public:
FnProperties(const TargetMachine & TM,const Function & F)704c4b7184SStanislav Mekhanoshin     explicit FnProperties(const TargetMachine &TM, const Function &F) {
714c4b7184SStanislav Mekhanoshin       Features = TM.getSubtargetImpl(F)->getFeatureBits();
724c4b7184SStanislav Mekhanoshin 
734c4b7184SStanislav Mekhanoshin       for (unsigned I = 0; I < NumAttr; ++I)
744c4b7184SStanislav Mekhanoshin         if (F.hasFnAttribute(AttributeNames[I]))
754c4b7184SStanislav Mekhanoshin           Attributes[I] = F.getFnAttribute(AttributeNames[I]);
764c4b7184SStanislav Mekhanoshin     }
774c4b7184SStanislav Mekhanoshin 
operator ==(const FnProperties & Other) const784c4b7184SStanislav Mekhanoshin     bool operator == (const FnProperties &Other) const {
794c4b7184SStanislav Mekhanoshin       if ((Features & TargetFeatures) != (Other.Features & TargetFeatures))
804c4b7184SStanislav Mekhanoshin         return false;
814c4b7184SStanislav Mekhanoshin       for (unsigned I = 0; I < NumAttr; ++I)
824c4b7184SStanislav Mekhanoshin         if (Attributes[I] != Other.Attributes[I])
834c4b7184SStanislav Mekhanoshin           return false;
844c4b7184SStanislav Mekhanoshin       return true;
854c4b7184SStanislav Mekhanoshin     }
864c4b7184SStanislav Mekhanoshin 
adjustToCaller(const FnProperties & CallerProps) const874c4b7184SStanislav Mekhanoshin     FnProperties adjustToCaller(const FnProperties &CallerProps) const {
884c4b7184SStanislav Mekhanoshin       FnProperties New((Features & ~TargetFeatures) | CallerProps.Features);
894c4b7184SStanislav Mekhanoshin       for (unsigned I = 0; I < NumAttr; ++I)
904c4b7184SStanislav Mekhanoshin         New.Attributes[I] = CallerProps.Attributes[I];
914c4b7184SStanislav Mekhanoshin       return New;
924c4b7184SStanislav Mekhanoshin     }
934c4b7184SStanislav Mekhanoshin 
944c4b7184SStanislav Mekhanoshin     FeatureBitset Features;
954c4b7184SStanislav Mekhanoshin     Optional<Attribute> Attributes[NumAttr];
964c4b7184SStanislav Mekhanoshin   };
974c4b7184SStanislav Mekhanoshin 
98ad04e7adSStanislav Mekhanoshin   class Clone {
99ad04e7adSStanislav Mekhanoshin   public:
Clone(const FnProperties & Props,Function * OrigF,Function * NewF)1004c4b7184SStanislav Mekhanoshin     Clone(const FnProperties &Props, Function *OrigF, Function *NewF) :
1014c4b7184SStanislav Mekhanoshin       Properties(Props), OrigF(OrigF), NewF(NewF) {}
102ad04e7adSStanislav Mekhanoshin 
1034c4b7184SStanislav Mekhanoshin     FnProperties Properties;
104ad04e7adSStanislav Mekhanoshin     Function *OrigF;
105ad04e7adSStanislav Mekhanoshin     Function *NewF;
106ad04e7adSStanislav Mekhanoshin   };
107ad04e7adSStanislav Mekhanoshin 
108ad04e7adSStanislav Mekhanoshin   const TargetMachine *TM;
109ad04e7adSStanislav Mekhanoshin 
110ad04e7adSStanislav Mekhanoshin   // Clone functions as needed or just set attributes.
111ad04e7adSStanislav Mekhanoshin   bool AllowClone;
112ad04e7adSStanislav Mekhanoshin 
113ad04e7adSStanislav Mekhanoshin   // Option propagation roots.
114ad04e7adSStanislav Mekhanoshin   SmallSet<Function *, 32> Roots;
115ad04e7adSStanislav Mekhanoshin 
116ad04e7adSStanislav Mekhanoshin   // Clones of functions with their attributes.
117ad04e7adSStanislav Mekhanoshin   SmallVector<Clone, 32> Clones;
118ad04e7adSStanislav Mekhanoshin 
119ad04e7adSStanislav Mekhanoshin   // Find a clone with required features.
1204c4b7184SStanislav Mekhanoshin   Function *findFunction(const FnProperties &PropsNeeded,
121ad04e7adSStanislav Mekhanoshin                          Function *OrigF);
122ad04e7adSStanislav Mekhanoshin 
1234c4b7184SStanislav Mekhanoshin   // Clone function \p F and set \p NewProps on the clone.
124ad04e7adSStanislav Mekhanoshin   // Cole takes the name of original function.
1254c4b7184SStanislav Mekhanoshin   Function *cloneWithProperties(Function &F, const FnProperties &NewProps);
126ad04e7adSStanislav Mekhanoshin 
127ad04e7adSStanislav Mekhanoshin   // Set new function's features in place.
128ad04e7adSStanislav Mekhanoshin   void setFeatures(Function &F, const FeatureBitset &NewFeatures);
129ad04e7adSStanislav Mekhanoshin 
1304c4b7184SStanislav Mekhanoshin   // Set new function's attributes in place.
1314c4b7184SStanislav Mekhanoshin   void setAttributes(Function &F, const ArrayRef<Optional<Attribute>> NewAttrs);
1324c4b7184SStanislav Mekhanoshin 
133ad04e7adSStanislav Mekhanoshin   std::string getFeatureString(const FeatureBitset &Features) const;
134ad04e7adSStanislav Mekhanoshin 
135ad04e7adSStanislav Mekhanoshin   // Propagate attributes from Roots.
136ad04e7adSStanislav Mekhanoshin   bool process();
137ad04e7adSStanislav Mekhanoshin 
138ad04e7adSStanislav Mekhanoshin public:
AMDGPUPropagateAttributes(const TargetMachine * TM,bool AllowClone)139660cae84SJon Chesterfield   AMDGPUPropagateAttributes(const TargetMachine *TM, bool AllowClone) :
140660cae84SJon Chesterfield     TM(TM), AllowClone(AllowClone) {}
141ad04e7adSStanislav Mekhanoshin 
142ad04e7adSStanislav Mekhanoshin   // Use F as a root and propagate its attributes.
143ad04e7adSStanislav Mekhanoshin   bool process(Function &F);
144ad04e7adSStanislav Mekhanoshin 
145ad04e7adSStanislav Mekhanoshin   // Propagate attributes starting from kernel functions.
146660cae84SJon Chesterfield   bool process(Module &M);
147ad04e7adSStanislav Mekhanoshin };
148ad04e7adSStanislav Mekhanoshin 
149dc6e8dfdSJacob Lambert // Allows to propagate attributes early, but no cloning is allowed as it must
150ad04e7adSStanislav Mekhanoshin // be a function pass to run before any optimizations.
151ad04e7adSStanislav Mekhanoshin // TODO: We shall only need a one instance of module pass, but that needs to be
152ad04e7adSStanislav Mekhanoshin // in the linker pipeline which is currently not possible.
153ad04e7adSStanislav Mekhanoshin class AMDGPUPropagateAttributesEarly : public FunctionPass {
154ad04e7adSStanislav Mekhanoshin   const TargetMachine *TM;
155ad04e7adSStanislav Mekhanoshin 
156ad04e7adSStanislav Mekhanoshin public:
157ad04e7adSStanislav Mekhanoshin   static char ID; // Pass identification
158ad04e7adSStanislav Mekhanoshin 
AMDGPUPropagateAttributesEarly(const TargetMachine * TM=nullptr)159ad04e7adSStanislav Mekhanoshin   AMDGPUPropagateAttributesEarly(const TargetMachine *TM = nullptr) :
160ad04e7adSStanislav Mekhanoshin     FunctionPass(ID), TM(TM) {
161ad04e7adSStanislav Mekhanoshin     initializeAMDGPUPropagateAttributesEarlyPass(
162ad04e7adSStanislav Mekhanoshin       *PassRegistry::getPassRegistry());
163ad04e7adSStanislav Mekhanoshin   }
164ad04e7adSStanislav Mekhanoshin 
165ad04e7adSStanislav Mekhanoshin   bool runOnFunction(Function &F) override;
166ad04e7adSStanislav Mekhanoshin };
167ad04e7adSStanislav Mekhanoshin 
168dc6e8dfdSJacob Lambert // Allows to propagate attributes with cloning but does that late in the
169ad04e7adSStanislav Mekhanoshin // pipeline.
170ad04e7adSStanislav Mekhanoshin class AMDGPUPropagateAttributesLate : public ModulePass {
171ad04e7adSStanislav Mekhanoshin   const TargetMachine *TM;
172ad04e7adSStanislav Mekhanoshin 
173ad04e7adSStanislav Mekhanoshin public:
174ad04e7adSStanislav Mekhanoshin   static char ID; // Pass identification
175ad04e7adSStanislav Mekhanoshin 
AMDGPUPropagateAttributesLate(const TargetMachine * TM=nullptr)176ad04e7adSStanislav Mekhanoshin   AMDGPUPropagateAttributesLate(const TargetMachine *TM = nullptr) :
177ad04e7adSStanislav Mekhanoshin     ModulePass(ID), TM(TM) {
178ad04e7adSStanislav Mekhanoshin     initializeAMDGPUPropagateAttributesLatePass(
179ad04e7adSStanislav Mekhanoshin       *PassRegistry::getPassRegistry());
180ad04e7adSStanislav Mekhanoshin   }
181ad04e7adSStanislav Mekhanoshin 
182ad04e7adSStanislav Mekhanoshin   bool runOnModule(Module &M) override;
183ad04e7adSStanislav Mekhanoshin };
184ad04e7adSStanislav Mekhanoshin 
185ad04e7adSStanislav Mekhanoshin }  // end anonymous namespace.
186ad04e7adSStanislav Mekhanoshin 
187ad04e7adSStanislav Mekhanoshin char AMDGPUPropagateAttributesEarly::ID = 0;
188ad04e7adSStanislav Mekhanoshin char AMDGPUPropagateAttributesLate::ID = 0;
189ad04e7adSStanislav Mekhanoshin 
190ad04e7adSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUPropagateAttributesEarly,
191ad04e7adSStanislav Mekhanoshin                 "amdgpu-propagate-attributes-early",
192ad04e7adSStanislav Mekhanoshin                 "Early propagate attributes from kernels to functions",
193ad04e7adSStanislav Mekhanoshin                 false, false)
194ad04e7adSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUPropagateAttributesLate,
195ad04e7adSStanislav Mekhanoshin                 "amdgpu-propagate-attributes-late",
196ad04e7adSStanislav Mekhanoshin                 "Late propagate attributes from kernels to functions",
197ad04e7adSStanislav Mekhanoshin                 false, false)
198ad04e7adSStanislav Mekhanoshin 
199ad04e7adSStanislav Mekhanoshin Function *
findFunction(const FnProperties & PropsNeeded,Function * OrigF)2004c4b7184SStanislav Mekhanoshin AMDGPUPropagateAttributes::findFunction(const FnProperties &PropsNeeded,
201ad04e7adSStanislav Mekhanoshin                                         Function *OrigF) {
202ad04e7adSStanislav Mekhanoshin   // TODO: search for clone's clones.
203ad04e7adSStanislav Mekhanoshin   for (Clone &C : Clones)
2044c4b7184SStanislav Mekhanoshin     if (C.OrigF == OrigF && PropsNeeded == C.Properties)
205ad04e7adSStanislav Mekhanoshin       return C.NewF;
206ad04e7adSStanislav Mekhanoshin 
207ad04e7adSStanislav Mekhanoshin   return nullptr;
208ad04e7adSStanislav Mekhanoshin }
209ad04e7adSStanislav Mekhanoshin 
process(Module & M)210660cae84SJon Chesterfield bool AMDGPUPropagateAttributes::process(Module &M) {
211ad04e7adSStanislav Mekhanoshin   for (auto &F : M.functions())
2122ac53fffSPiotr Sobczak     if (AMDGPU::isKernel(F.getCallingConv()))
213ad04e7adSStanislav Mekhanoshin       Roots.insert(&F);
214ad04e7adSStanislav Mekhanoshin 
2152ac53fffSPiotr Sobczak   return Roots.empty() ? false : process();
216ad04e7adSStanislav Mekhanoshin }
217ad04e7adSStanislav Mekhanoshin 
process(Function & F)218ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributes::process(Function &F) {
219ad04e7adSStanislav Mekhanoshin   Roots.insert(&F);
220ad04e7adSStanislav Mekhanoshin   return process();
221ad04e7adSStanislav Mekhanoshin }
222ad04e7adSStanislav Mekhanoshin 
process()223ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributes::process() {
224ad04e7adSStanislav Mekhanoshin   bool Changed = false;
225ad04e7adSStanislav Mekhanoshin   SmallSet<Function *, 32> NewRoots;
226ad04e7adSStanislav Mekhanoshin   SmallSet<Function *, 32> Replaced;
227ad04e7adSStanislav Mekhanoshin 
2282ac53fffSPiotr Sobczak   assert(!Roots.empty());
229ad04e7adSStanislav Mekhanoshin   Module &M = *(*Roots.begin())->getParent();
230ad04e7adSStanislav Mekhanoshin 
231ad04e7adSStanislav Mekhanoshin   do {
232ad04e7adSStanislav Mekhanoshin     Roots.insert(NewRoots.begin(), NewRoots.end());
233ad04e7adSStanislav Mekhanoshin     NewRoots.clear();
234ad04e7adSStanislav Mekhanoshin 
235ad04e7adSStanislav Mekhanoshin     for (auto &F : M.functions()) {
236e06d707aSStanislav Mekhanoshin       if (F.isDeclaration())
237ad04e7adSStanislav Mekhanoshin         continue;
238ad04e7adSStanislav Mekhanoshin 
2394c4b7184SStanislav Mekhanoshin       const FnProperties CalleeProps(*TM, F);
240ad04e7adSStanislav Mekhanoshin       SmallVector<std::pair<CallBase *, Function *>, 32> ToReplace;
241e06d707aSStanislav Mekhanoshin       SmallSet<CallBase *, 32> Visited;
242ad04e7adSStanislav Mekhanoshin 
243ad04e7adSStanislav Mekhanoshin       for (User *U : F.users()) {
244ad04e7adSStanislav Mekhanoshin         Instruction *I = dyn_cast<Instruction>(U);
245ad04e7adSStanislav Mekhanoshin         if (!I)
246ad04e7adSStanislav Mekhanoshin           continue;
247ad04e7adSStanislav Mekhanoshin         CallBase *CI = dyn_cast<CallBase>(I);
248fcd32d62Sjweightma         // Only propagate attributes if F is the called function. Specifically,
249fcd32d62Sjweightma         // do not propagate attributes if F is passed as an argument.
250fcd32d62Sjweightma         // FIXME: handle bitcasted callee, e.g.
251fcd32d62Sjweightma         // %retval = call i8* bitcast (i32* ()* @f to i8* ()*)()
252fcd32d62Sjweightma         if (!CI || CI->getCalledOperand() != &F)
253ad04e7adSStanislav Mekhanoshin           continue;
254ad04e7adSStanislav Mekhanoshin         Function *Caller = CI->getCaller();
255e06d707aSStanislav Mekhanoshin         if (!Caller || !Visited.insert(CI).second)
256ad04e7adSStanislav Mekhanoshin           continue;
257e06d707aSStanislav Mekhanoshin         if (!Roots.count(Caller) && !NewRoots.count(Caller))
258ad04e7adSStanislav Mekhanoshin           continue;
259ad04e7adSStanislav Mekhanoshin 
2604c4b7184SStanislav Mekhanoshin         const FnProperties CallerProps(*TM, *Caller);
261ad04e7adSStanislav Mekhanoshin 
2622cdb34efSKonstantin Zhuravlyov         if (CalleeProps == CallerProps) {
263e06d707aSStanislav Mekhanoshin           if (!Roots.count(&F))
264ad04e7adSStanislav Mekhanoshin             NewRoots.insert(&F);
265ad04e7adSStanislav Mekhanoshin           continue;
266ad04e7adSStanislav Mekhanoshin         }
267ad04e7adSStanislav Mekhanoshin 
2684c4b7184SStanislav Mekhanoshin         Function *NewF = findFunction(CallerProps, &F);
269ad04e7adSStanislav Mekhanoshin         if (!NewF) {
2704c4b7184SStanislav Mekhanoshin           const FnProperties NewProps = CalleeProps.adjustToCaller(CallerProps);
271ad04e7adSStanislav Mekhanoshin           if (!AllowClone) {
272dc6e8dfdSJacob Lambert             // This may set different features on different iterations if
273ad04e7adSStanislav Mekhanoshin             // there is a contradiction in callers' attributes. In this case
274ad04e7adSStanislav Mekhanoshin             // we rely on a second pass running on Module, which is allowed
275ad04e7adSStanislav Mekhanoshin             // to clone.
2764c4b7184SStanislav Mekhanoshin             setFeatures(F, NewProps.Features);
2774c4b7184SStanislav Mekhanoshin             setAttributes(F, NewProps.Attributes);
278ad04e7adSStanislav Mekhanoshin             NewRoots.insert(&F);
279ad04e7adSStanislav Mekhanoshin             Changed = true;
280ad04e7adSStanislav Mekhanoshin             break;
281ad04e7adSStanislav Mekhanoshin           }
282ad04e7adSStanislav Mekhanoshin 
2834c4b7184SStanislav Mekhanoshin           NewF = cloneWithProperties(F, NewProps);
2844c4b7184SStanislav Mekhanoshin           Clones.push_back(Clone(CallerProps, &F, NewF));
285ad04e7adSStanislav Mekhanoshin           NewRoots.insert(NewF);
286ad04e7adSStanislav Mekhanoshin         }
287ad04e7adSStanislav Mekhanoshin 
288ad04e7adSStanislav Mekhanoshin         ToReplace.push_back(std::make_pair(CI, NewF));
289ad04e7adSStanislav Mekhanoshin         Replaced.insert(&F);
290ad04e7adSStanislav Mekhanoshin 
291ad04e7adSStanislav Mekhanoshin         Changed = true;
292ad04e7adSStanislav Mekhanoshin       }
293ad04e7adSStanislav Mekhanoshin 
294ad04e7adSStanislav Mekhanoshin       while (!ToReplace.empty()) {
295ad04e7adSStanislav Mekhanoshin         auto R = ToReplace.pop_back_val();
296ad04e7adSStanislav Mekhanoshin         R.first->setCalledFunction(R.second);
297ad04e7adSStanislav Mekhanoshin       }
298ad04e7adSStanislav Mekhanoshin     }
299ad04e7adSStanislav Mekhanoshin   } while (!NewRoots.empty());
300ad04e7adSStanislav Mekhanoshin 
301ad04e7adSStanislav Mekhanoshin   for (Function *F : Replaced) {
302ad04e7adSStanislav Mekhanoshin     if (F->use_empty())
303ad04e7adSStanislav Mekhanoshin       F->eraseFromParent();
304ad04e7adSStanislav Mekhanoshin   }
305ad04e7adSStanislav Mekhanoshin 
306e06d707aSStanislav Mekhanoshin   Roots.clear();
307e06d707aSStanislav Mekhanoshin   Clones.clear();
308e06d707aSStanislav Mekhanoshin 
309ad04e7adSStanislav Mekhanoshin   return Changed;
310ad04e7adSStanislav Mekhanoshin }
311ad04e7adSStanislav Mekhanoshin 
312ad04e7adSStanislav Mekhanoshin Function *
cloneWithProperties(Function & F,const FnProperties & NewProps)3134c4b7184SStanislav Mekhanoshin AMDGPUPropagateAttributes::cloneWithProperties(Function &F,
3144c4b7184SStanislav Mekhanoshin                                                const FnProperties &NewProps) {
315ad04e7adSStanislav Mekhanoshin   LLVM_DEBUG(dbgs() << "Cloning " << F.getName() << '\n');
316ad04e7adSStanislav Mekhanoshin 
317ad04e7adSStanislav Mekhanoshin   ValueToValueMapTy dummy;
318ad04e7adSStanislav Mekhanoshin   Function *NewF = CloneFunction(&F, dummy);
3194c4b7184SStanislav Mekhanoshin   setFeatures(*NewF, NewProps.Features);
3204c4b7184SStanislav Mekhanoshin   setAttributes(*NewF, NewProps.Attributes);
3216e00e3fcSStanislav Mekhanoshin   NewF->setVisibility(GlobalValue::DefaultVisibility);
3226e00e3fcSStanislav Mekhanoshin   NewF->setLinkage(GlobalValue::InternalLinkage);
323ad04e7adSStanislav Mekhanoshin 
324ad04e7adSStanislav Mekhanoshin   // Swap names. If that is the only clone it will retain the name of now
3256e00e3fcSStanislav Mekhanoshin   // dead value. Preserve original name for externally visible functions.
3266e00e3fcSStanislav Mekhanoshin   if (F.hasName() && F.hasLocalLinkage()) {
327adcd0268SBenjamin Kramer     std::string NewName = std::string(NewF->getName());
328ad04e7adSStanislav Mekhanoshin     NewF->takeName(&F);
329ad04e7adSStanislav Mekhanoshin     F.setName(NewName);
330ad04e7adSStanislav Mekhanoshin   }
331ad04e7adSStanislav Mekhanoshin 
332ad04e7adSStanislav Mekhanoshin   return NewF;
333ad04e7adSStanislav Mekhanoshin }
334ad04e7adSStanislav Mekhanoshin 
setFeatures(Function & F,const FeatureBitset & NewFeatures)335ad04e7adSStanislav Mekhanoshin void AMDGPUPropagateAttributes::setFeatures(Function &F,
336ad04e7adSStanislav Mekhanoshin                                             const FeatureBitset &NewFeatures) {
337ad04e7adSStanislav Mekhanoshin   std::string NewFeatureStr = getFeatureString(NewFeatures);
338ad04e7adSStanislav Mekhanoshin 
339ad04e7adSStanislav Mekhanoshin   LLVM_DEBUG(dbgs() << "Set features "
340ad04e7adSStanislav Mekhanoshin                     << getFeatureString(NewFeatures & TargetFeatures)
341ad04e7adSStanislav Mekhanoshin                     << " on " << F.getName() << '\n');
342ad04e7adSStanislav Mekhanoshin 
343ad04e7adSStanislav Mekhanoshin   F.removeFnAttr("target-features");
344ad04e7adSStanislav Mekhanoshin   F.addFnAttr("target-features", NewFeatureStr);
345ad04e7adSStanislav Mekhanoshin }
346ad04e7adSStanislav Mekhanoshin 
setAttributes(Function & F,const ArrayRef<Optional<Attribute>> NewAttrs)3474c4b7184SStanislav Mekhanoshin void AMDGPUPropagateAttributes::setAttributes(Function &F,
3484c4b7184SStanislav Mekhanoshin     const ArrayRef<Optional<Attribute>> NewAttrs) {
3494c4b7184SStanislav Mekhanoshin   LLVM_DEBUG(dbgs() << "Set attributes on " << F.getName() << ":\n");
3504c4b7184SStanislav Mekhanoshin   for (unsigned I = 0; I < NumAttr; ++I) {
3514c4b7184SStanislav Mekhanoshin     F.removeFnAttr(AttributeNames[I]);
3524c4b7184SStanislav Mekhanoshin     if (NewAttrs[I]) {
3534c4b7184SStanislav Mekhanoshin       LLVM_DEBUG(dbgs() << '\t' << NewAttrs[I]->getAsString() << '\n');
3544c4b7184SStanislav Mekhanoshin       F.addFnAttr(*NewAttrs[I]);
3554c4b7184SStanislav Mekhanoshin     }
3564c4b7184SStanislav Mekhanoshin   }
3574c4b7184SStanislav Mekhanoshin }
3584c4b7184SStanislav Mekhanoshin 
359ad04e7adSStanislav Mekhanoshin std::string
getFeatureString(const FeatureBitset & Features) const360ad04e7adSStanislav Mekhanoshin AMDGPUPropagateAttributes::getFeatureString(const FeatureBitset &Features) const
361ad04e7adSStanislav Mekhanoshin {
362ad04e7adSStanislav Mekhanoshin   std::string Ret;
363ad04e7adSStanislav Mekhanoshin   for (const SubtargetFeatureKV &KV : AMDGPUFeatureKV) {
364ad04e7adSStanislav Mekhanoshin     if (Features[KV.Value])
365ad04e7adSStanislav Mekhanoshin       Ret += (StringRef("+") + KV.Key + ",").str();
366ad04e7adSStanislav Mekhanoshin     else if (TargetFeatures[KV.Value])
367ad04e7adSStanislav Mekhanoshin       Ret += (StringRef("-") + KV.Key + ",").str();
368ad04e7adSStanislav Mekhanoshin   }
369ad04e7adSStanislav Mekhanoshin   Ret.pop_back(); // Remove last comma.
370ad04e7adSStanislav Mekhanoshin   return Ret;
371ad04e7adSStanislav Mekhanoshin }
372ad04e7adSStanislav Mekhanoshin 
runOnFunction(Function & F)373ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributesEarly::runOnFunction(Function &F) {
37453c43431SMatt Arsenault   if (!TM) {
37553c43431SMatt Arsenault     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
37653c43431SMatt Arsenault     if (!TPC)
37753c43431SMatt Arsenault       return false;
37853c43431SMatt Arsenault 
37953c43431SMatt Arsenault     TM = &TPC->getTM<TargetMachine>();
38053c43431SMatt Arsenault   }
38153c43431SMatt Arsenault 
3822ac53fffSPiotr Sobczak   if (!AMDGPU::isKernel(F.getCallingConv()))
383ad04e7adSStanislav Mekhanoshin     return false;
384ad04e7adSStanislav Mekhanoshin 
385ad04e7adSStanislav Mekhanoshin   return AMDGPUPropagateAttributes(TM, false).process(F);
386ad04e7adSStanislav Mekhanoshin }
387ad04e7adSStanislav Mekhanoshin 
runOnModule(Module & M)388ad04e7adSStanislav Mekhanoshin bool AMDGPUPropagateAttributesLate::runOnModule(Module &M) {
38953c43431SMatt Arsenault   if (!TM) {
39053c43431SMatt Arsenault     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
39153c43431SMatt Arsenault     if (!TPC)
392ad04e7adSStanislav Mekhanoshin       return false;
393ad04e7adSStanislav Mekhanoshin 
39453c43431SMatt Arsenault     TM = &TPC->getTM<TargetMachine>();
39553c43431SMatt Arsenault   }
396660cae84SJon Chesterfield 
397660cae84SJon Chesterfield   return AMDGPUPropagateAttributes(TM, true).process(M);
398ad04e7adSStanislav Mekhanoshin }
399ad04e7adSStanislav Mekhanoshin 
400ad04e7adSStanislav Mekhanoshin FunctionPass
createAMDGPUPropagateAttributesEarlyPass(const TargetMachine * TM)401ad04e7adSStanislav Mekhanoshin *llvm::createAMDGPUPropagateAttributesEarlyPass(const TargetMachine *TM) {
402ad04e7adSStanislav Mekhanoshin   return new AMDGPUPropagateAttributesEarly(TM);
403ad04e7adSStanislav Mekhanoshin }
404ad04e7adSStanislav Mekhanoshin 
405ad04e7adSStanislav Mekhanoshin ModulePass
createAMDGPUPropagateAttributesLatePass(const TargetMachine * TM)406ad04e7adSStanislav Mekhanoshin *llvm::createAMDGPUPropagateAttributesLatePass(const TargetMachine *TM) {
407ad04e7adSStanislav Mekhanoshin   return new AMDGPUPropagateAttributesLate(TM);
408ad04e7adSStanislav Mekhanoshin }
409a5f863e0SArthur Eubanks 
410a5f863e0SArthur Eubanks PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)411a5f863e0SArthur Eubanks AMDGPUPropagateAttributesEarlyPass::run(Function &F,
412a5f863e0SArthur Eubanks                                         FunctionAnalysisManager &AM) {
413a5f863e0SArthur Eubanks   if (!AMDGPU::isEntryFunctionCC(F.getCallingConv()))
414a5f863e0SArthur Eubanks     return PreservedAnalyses::all();
415a5f863e0SArthur Eubanks 
416a5f863e0SArthur Eubanks   return AMDGPUPropagateAttributes(&TM, false).process(F)
417a5f863e0SArthur Eubanks              ? PreservedAnalyses::none()
418a5f863e0SArthur Eubanks              : PreservedAnalyses::all();
419a5f863e0SArthur Eubanks }
420a5f863e0SArthur Eubanks 
421a5f863e0SArthur Eubanks PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)422660cae84SJon Chesterfield AMDGPUPropagateAttributesLatePass::run(Module &M, ModuleAnalysisManager &AM) {
423660cae84SJon Chesterfield   return AMDGPUPropagateAttributes(&TM, true).process(M)
424660cae84SJon Chesterfield              ? PreservedAnalyses::none()
425660cae84SJon Chesterfield              : PreservedAnalyses::all();
426a5f863e0SArthur Eubanks }
427