10b57cec5SDimitry Andric //===--- AMDGPUPropagateAttributes.cpp --------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// \brief This pass propagates attributes from kernels to the non-entry
110b57cec5SDimitry Andric /// functions. Most of the library functions were not compiled for specific ABI,
120b57cec5SDimitry Andric /// yet will be correctly compiled if proper attrbutes are propagated from the
130b57cec5SDimitry Andric /// caller.
140b57cec5SDimitry Andric ///
150b57cec5SDimitry Andric /// The pass analyzes call graph and propagates ABI target features through the
160b57cec5SDimitry Andric /// call graph.
170b57cec5SDimitry Andric ///
180b57cec5SDimitry Andric /// It can run in two modes: as a function or module pass. A function pass
190b57cec5SDimitry Andric /// simply propagates attributes. A module pass clones functions if there are
200b57cec5SDimitry Andric /// callers with different ABI. If a function is clonned all call sites will
210b57cec5SDimitry Andric /// be updated to use a correct clone.
220b57cec5SDimitry Andric ///
230b57cec5SDimitry Andric /// A function pass is limited in functionality but can run early in the
240b57cec5SDimitry Andric /// pipeline. A module pass is more powerful but has to run late, so misses
250b57cec5SDimitry Andric /// library folding opportunities.
260b57cec5SDimitry Andric //
270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #include "AMDGPU.h"
300b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
310b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
320b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
33af732203SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
34af732203SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
35af732203SDimitry Andric #include "llvm/IR/InstrTypes.h"
360b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
370b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-propagate-attributes"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace llvm;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric namespace llvm {
440b57cec5SDimitry Andric extern const SubtargetFeatureKV AMDGPUFeatureKV[AMDGPU::NumSubtargetFeatures-1];
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric namespace {
480b57cec5SDimitry Andric 
495ffd83dbSDimitry Andric // Target features to propagate.
505ffd83dbSDimitry Andric static constexpr const FeatureBitset TargetFeatures = {
510b57cec5SDimitry Andric   AMDGPU::FeatureWavefrontSize16,
520b57cec5SDimitry Andric   AMDGPU::FeatureWavefrontSize32,
530b57cec5SDimitry Andric   AMDGPU::FeatureWavefrontSize64
540b57cec5SDimitry Andric };
550b57cec5SDimitry Andric 
565ffd83dbSDimitry Andric // Attributes to propagate.
57af732203SDimitry Andric // TODO: Support conservative min/max merging instead of cloning.
585ffd83dbSDimitry Andric static constexpr const char* AttributeNames[] = {
59af732203SDimitry Andric   "amdgpu-waves-per-eu",
60af732203SDimitry Andric   "amdgpu-flat-work-group-size"
615ffd83dbSDimitry Andric };
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric static constexpr unsigned NumAttr =
645ffd83dbSDimitry Andric   sizeof(AttributeNames) / sizeof(AttributeNames[0]);
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric class AMDGPUPropagateAttributes {
675ffd83dbSDimitry Andric 
685ffd83dbSDimitry Andric   class FnProperties {
695ffd83dbSDimitry Andric   private:
FnProperties(const FeatureBitset && FB)705ffd83dbSDimitry Andric     explicit FnProperties(const FeatureBitset &&FB) : Features(FB) {}
715ffd83dbSDimitry Andric 
725ffd83dbSDimitry Andric   public:
FnProperties(const TargetMachine & TM,const Function & F)735ffd83dbSDimitry Andric     explicit FnProperties(const TargetMachine &TM, const Function &F) {
745ffd83dbSDimitry Andric       Features = TM.getSubtargetImpl(F)->getFeatureBits();
755ffd83dbSDimitry Andric 
765ffd83dbSDimitry Andric       for (unsigned I = 0; I < NumAttr; ++I)
775ffd83dbSDimitry Andric         if (F.hasFnAttribute(AttributeNames[I]))
785ffd83dbSDimitry Andric           Attributes[I] = F.getFnAttribute(AttributeNames[I]);
795ffd83dbSDimitry Andric     }
805ffd83dbSDimitry Andric 
operator ==(const FnProperties & Other) const815ffd83dbSDimitry Andric     bool operator == (const FnProperties &Other) const {
825ffd83dbSDimitry Andric       if ((Features & TargetFeatures) != (Other.Features & TargetFeatures))
835ffd83dbSDimitry Andric         return false;
845ffd83dbSDimitry Andric       for (unsigned I = 0; I < NumAttr; ++I)
855ffd83dbSDimitry Andric         if (Attributes[I] != Other.Attributes[I])
865ffd83dbSDimitry Andric           return false;
875ffd83dbSDimitry Andric       return true;
885ffd83dbSDimitry Andric     }
895ffd83dbSDimitry Andric 
adjustToCaller(const FnProperties & CallerProps) const905ffd83dbSDimitry Andric     FnProperties adjustToCaller(const FnProperties &CallerProps) const {
915ffd83dbSDimitry Andric       FnProperties New((Features & ~TargetFeatures) | CallerProps.Features);
925ffd83dbSDimitry Andric       for (unsigned I = 0; I < NumAttr; ++I)
935ffd83dbSDimitry Andric         New.Attributes[I] = CallerProps.Attributes[I];
945ffd83dbSDimitry Andric       return New;
955ffd83dbSDimitry Andric     }
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric     FeatureBitset Features;
985ffd83dbSDimitry Andric     Optional<Attribute> Attributes[NumAttr];
995ffd83dbSDimitry Andric   };
1005ffd83dbSDimitry Andric 
1010b57cec5SDimitry Andric   class Clone {
1020b57cec5SDimitry Andric   public:
Clone(const FnProperties & Props,Function * OrigF,Function * NewF)1035ffd83dbSDimitry Andric     Clone(const FnProperties &Props, Function *OrigF, Function *NewF) :
1045ffd83dbSDimitry Andric       Properties(Props), OrigF(OrigF), NewF(NewF) {}
1050b57cec5SDimitry Andric 
1065ffd83dbSDimitry Andric     FnProperties Properties;
1070b57cec5SDimitry Andric     Function *OrigF;
1080b57cec5SDimitry Andric     Function *NewF;
1090b57cec5SDimitry Andric   };
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   const TargetMachine *TM;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   // Clone functions as needed or just set attributes.
1140b57cec5SDimitry Andric   bool AllowClone;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   // Option propagation roots.
1170b57cec5SDimitry Andric   SmallSet<Function *, 32> Roots;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   // Clones of functions with their attributes.
1200b57cec5SDimitry Andric   SmallVector<Clone, 32> Clones;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Find a clone with required features.
1235ffd83dbSDimitry Andric   Function *findFunction(const FnProperties &PropsNeeded,
1240b57cec5SDimitry Andric                          Function *OrigF);
1250b57cec5SDimitry Andric 
1265ffd83dbSDimitry Andric   // Clone function \p F and set \p NewProps on the clone.
1270b57cec5SDimitry Andric   // Cole takes the name of original function.
1285ffd83dbSDimitry Andric   Function *cloneWithProperties(Function &F, const FnProperties &NewProps);
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   // Set new function's features in place.
1310b57cec5SDimitry Andric   void setFeatures(Function &F, const FeatureBitset &NewFeatures);
1320b57cec5SDimitry Andric 
1335ffd83dbSDimitry Andric   // Set new function's attributes in place.
1345ffd83dbSDimitry Andric   void setAttributes(Function &F, const ArrayRef<Optional<Attribute>> NewAttrs);
1355ffd83dbSDimitry Andric 
1360b57cec5SDimitry Andric   std::string getFeatureString(const FeatureBitset &Features) const;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // Propagate attributes from Roots.
1390b57cec5SDimitry Andric   bool process();
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric public:
AMDGPUPropagateAttributes(const TargetMachine * TM,bool AllowClone)1420b57cec5SDimitry Andric   AMDGPUPropagateAttributes(const TargetMachine *TM, bool AllowClone) :
1430b57cec5SDimitry Andric     TM(TM), AllowClone(AllowClone) {}
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   // Use F as a root and propagate its attributes.
1460b57cec5SDimitry Andric   bool process(Function &F);
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   // Propagate attributes starting from kernel functions.
1490b57cec5SDimitry Andric   bool process(Module &M);
1500b57cec5SDimitry Andric };
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric // Allows to propagate attributes early, but no clonning is allowed as it must
1530b57cec5SDimitry Andric // be a function pass to run before any optimizations.
1540b57cec5SDimitry Andric // TODO: We shall only need a one instance of module pass, but that needs to be
1550b57cec5SDimitry Andric // in the linker pipeline which is currently not possible.
1560b57cec5SDimitry Andric class AMDGPUPropagateAttributesEarly : public FunctionPass {
1570b57cec5SDimitry Andric   const TargetMachine *TM;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric public:
1600b57cec5SDimitry Andric   static char ID; // Pass identification
1610b57cec5SDimitry Andric 
AMDGPUPropagateAttributesEarly(const TargetMachine * TM=nullptr)1620b57cec5SDimitry Andric   AMDGPUPropagateAttributesEarly(const TargetMachine *TM = nullptr) :
1630b57cec5SDimitry Andric     FunctionPass(ID), TM(TM) {
1640b57cec5SDimitry Andric     initializeAMDGPUPropagateAttributesEarlyPass(
1650b57cec5SDimitry Andric       *PassRegistry::getPassRegistry());
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   bool runOnFunction(Function &F) override;
1690b57cec5SDimitry Andric };
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric // Allows to propagate attributes with clonning but does that late in the
1720b57cec5SDimitry Andric // pipeline.
1730b57cec5SDimitry Andric class AMDGPUPropagateAttributesLate : public ModulePass {
1740b57cec5SDimitry Andric   const TargetMachine *TM;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric public:
1770b57cec5SDimitry Andric   static char ID; // Pass identification
1780b57cec5SDimitry Andric 
AMDGPUPropagateAttributesLate(const TargetMachine * TM=nullptr)1790b57cec5SDimitry Andric   AMDGPUPropagateAttributesLate(const TargetMachine *TM = nullptr) :
1800b57cec5SDimitry Andric     ModulePass(ID), TM(TM) {
1810b57cec5SDimitry Andric     initializeAMDGPUPropagateAttributesLatePass(
1820b57cec5SDimitry Andric       *PassRegistry::getPassRegistry());
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   bool runOnModule(Module &M) override;
1860b57cec5SDimitry Andric };
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric }  // end anonymous namespace.
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric char AMDGPUPropagateAttributesEarly::ID = 0;
1910b57cec5SDimitry Andric char AMDGPUPropagateAttributesLate::ID = 0;
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUPropagateAttributesEarly,
1940b57cec5SDimitry Andric                 "amdgpu-propagate-attributes-early",
1950b57cec5SDimitry Andric                 "Early propagate attributes from kernels to functions",
1960b57cec5SDimitry Andric                 false, false)
1970b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUPropagateAttributesLate,
1980b57cec5SDimitry Andric                 "amdgpu-propagate-attributes-late",
1990b57cec5SDimitry Andric                 "Late propagate attributes from kernels to functions",
2000b57cec5SDimitry Andric                 false, false)
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric Function *
findFunction(const FnProperties & PropsNeeded,Function * OrigF)2035ffd83dbSDimitry Andric AMDGPUPropagateAttributes::findFunction(const FnProperties &PropsNeeded,
2040b57cec5SDimitry Andric                                         Function *OrigF) {
2050b57cec5SDimitry Andric   // TODO: search for clone's clones.
2060b57cec5SDimitry Andric   for (Clone &C : Clones)
2075ffd83dbSDimitry Andric     if (C.OrigF == OrigF && PropsNeeded == C.Properties)
2080b57cec5SDimitry Andric       return C.NewF;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   return nullptr;
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
process(Module & M)2130b57cec5SDimitry Andric bool AMDGPUPropagateAttributes::process(Module &M) {
2140b57cec5SDimitry Andric   for (auto &F : M.functions())
2150b57cec5SDimitry Andric     if (AMDGPU::isEntryFunctionCC(F.getCallingConv()))
2160b57cec5SDimitry Andric       Roots.insert(&F);
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   return process();
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
process(Function & F)2210b57cec5SDimitry Andric bool AMDGPUPropagateAttributes::process(Function &F) {
2220b57cec5SDimitry Andric   Roots.insert(&F);
2230b57cec5SDimitry Andric   return process();
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
process()2260b57cec5SDimitry Andric bool AMDGPUPropagateAttributes::process() {
2270b57cec5SDimitry Andric   bool Changed = false;
2280b57cec5SDimitry Andric   SmallSet<Function *, 32> NewRoots;
2290b57cec5SDimitry Andric   SmallSet<Function *, 32> Replaced;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   if (Roots.empty())
2320b57cec5SDimitry Andric     return false;
2330b57cec5SDimitry Andric   Module &M = *(*Roots.begin())->getParent();
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   do {
2360b57cec5SDimitry Andric     Roots.insert(NewRoots.begin(), NewRoots.end());
2370b57cec5SDimitry Andric     NewRoots.clear();
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric     for (auto &F : M.functions()) {
2405ffd83dbSDimitry Andric       if (F.isDeclaration())
2410b57cec5SDimitry Andric         continue;
2420b57cec5SDimitry Andric 
2435ffd83dbSDimitry Andric       const FnProperties CalleeProps(*TM, F);
2440b57cec5SDimitry Andric       SmallVector<std::pair<CallBase *, Function *>, 32> ToReplace;
2455ffd83dbSDimitry Andric       SmallSet<CallBase *, 32> Visited;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric       for (User *U : F.users()) {
2480b57cec5SDimitry Andric         Instruction *I = dyn_cast<Instruction>(U);
2490b57cec5SDimitry Andric         if (!I)
2500b57cec5SDimitry Andric           continue;
2510b57cec5SDimitry Andric         CallBase *CI = dyn_cast<CallBase>(I);
252*5f7ddb14SDimitry Andric         // Only propagate attributes if F is the called function. Specifically,
253*5f7ddb14SDimitry Andric         // do not propagate attributes if F is passed as an argument.
254*5f7ddb14SDimitry Andric         // FIXME: handle bitcasted callee, e.g.
255*5f7ddb14SDimitry Andric         // %retval = call i8* bitcast (i32* ()* @f to i8* ()*)()
256*5f7ddb14SDimitry Andric         if (!CI || CI->getCalledOperand() != &F)
2570b57cec5SDimitry Andric           continue;
2580b57cec5SDimitry Andric         Function *Caller = CI->getCaller();
2595ffd83dbSDimitry Andric         if (!Caller || !Visited.insert(CI).second)
2600b57cec5SDimitry Andric           continue;
2615ffd83dbSDimitry Andric         if (!Roots.count(Caller) && !NewRoots.count(Caller))
2620b57cec5SDimitry Andric           continue;
2630b57cec5SDimitry Andric 
2645ffd83dbSDimitry Andric         const FnProperties CallerProps(*TM, *Caller);
2650b57cec5SDimitry Andric 
2665ffd83dbSDimitry Andric         if (CalleeProps == CallerProps) {
2675ffd83dbSDimitry Andric           if (!Roots.count(&F))
2680b57cec5SDimitry Andric             NewRoots.insert(&F);
2690b57cec5SDimitry Andric           continue;
2700b57cec5SDimitry Andric         }
2710b57cec5SDimitry Andric 
2725ffd83dbSDimitry Andric         Function *NewF = findFunction(CallerProps, &F);
2730b57cec5SDimitry Andric         if (!NewF) {
2745ffd83dbSDimitry Andric           const FnProperties NewProps = CalleeProps.adjustToCaller(CallerProps);
2750b57cec5SDimitry Andric           if (!AllowClone) {
2760b57cec5SDimitry Andric             // This may set different features on different iteartions if
2770b57cec5SDimitry Andric             // there is a contradiction in callers' attributes. In this case
2780b57cec5SDimitry Andric             // we rely on a second pass running on Module, which is allowed
2790b57cec5SDimitry Andric             // to clone.
2805ffd83dbSDimitry Andric             setFeatures(F, NewProps.Features);
2815ffd83dbSDimitry Andric             setAttributes(F, NewProps.Attributes);
2820b57cec5SDimitry Andric             NewRoots.insert(&F);
2830b57cec5SDimitry Andric             Changed = true;
2840b57cec5SDimitry Andric             break;
2850b57cec5SDimitry Andric           }
2860b57cec5SDimitry Andric 
2875ffd83dbSDimitry Andric           NewF = cloneWithProperties(F, NewProps);
2885ffd83dbSDimitry Andric           Clones.push_back(Clone(CallerProps, &F, NewF));
2890b57cec5SDimitry Andric           NewRoots.insert(NewF);
2900b57cec5SDimitry Andric         }
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric         ToReplace.push_back(std::make_pair(CI, NewF));
2930b57cec5SDimitry Andric         Replaced.insert(&F);
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric         Changed = true;
2960b57cec5SDimitry Andric       }
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric       while (!ToReplace.empty()) {
2990b57cec5SDimitry Andric         auto R = ToReplace.pop_back_val();
3000b57cec5SDimitry Andric         R.first->setCalledFunction(R.second);
3010b57cec5SDimitry Andric       }
3020b57cec5SDimitry Andric     }
3030b57cec5SDimitry Andric   } while (!NewRoots.empty());
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   for (Function *F : Replaced) {
3060b57cec5SDimitry Andric     if (F->use_empty())
3070b57cec5SDimitry Andric       F->eraseFromParent();
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric 
3105ffd83dbSDimitry Andric   Roots.clear();
3115ffd83dbSDimitry Andric   Clones.clear();
3125ffd83dbSDimitry Andric 
3130b57cec5SDimitry Andric   return Changed;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric Function *
cloneWithProperties(Function & F,const FnProperties & NewProps)3175ffd83dbSDimitry Andric AMDGPUPropagateAttributes::cloneWithProperties(Function &F,
3185ffd83dbSDimitry Andric                                                const FnProperties &NewProps) {
3190b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Cloning " << F.getName() << '\n');
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   ValueToValueMapTy dummy;
3220b57cec5SDimitry Andric   Function *NewF = CloneFunction(&F, dummy);
3235ffd83dbSDimitry Andric   setFeatures(*NewF, NewProps.Features);
3245ffd83dbSDimitry Andric   setAttributes(*NewF, NewProps.Attributes);
3255ffd83dbSDimitry Andric   NewF->setVisibility(GlobalValue::DefaultVisibility);
3265ffd83dbSDimitry Andric   NewF->setLinkage(GlobalValue::InternalLinkage);
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   // Swap names. If that is the only clone it will retain the name of now
3295ffd83dbSDimitry Andric   // dead value. Preserve original name for externally visible functions.
3305ffd83dbSDimitry Andric   if (F.hasName() && F.hasLocalLinkage()) {
3315ffd83dbSDimitry Andric     std::string NewName = std::string(NewF->getName());
3320b57cec5SDimitry Andric     NewF->takeName(&F);
3330b57cec5SDimitry Andric     F.setName(NewName);
3340b57cec5SDimitry Andric   }
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   return NewF;
3370b57cec5SDimitry Andric }
3380b57cec5SDimitry Andric 
setFeatures(Function & F,const FeatureBitset & NewFeatures)3390b57cec5SDimitry Andric void AMDGPUPropagateAttributes::setFeatures(Function &F,
3400b57cec5SDimitry Andric                                             const FeatureBitset &NewFeatures) {
3410b57cec5SDimitry Andric   std::string NewFeatureStr = getFeatureString(NewFeatures);
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Set features "
3440b57cec5SDimitry Andric                     << getFeatureString(NewFeatures & TargetFeatures)
3450b57cec5SDimitry Andric                     << " on " << F.getName() << '\n');
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   F.removeFnAttr("target-features");
3480b57cec5SDimitry Andric   F.addFnAttr("target-features", NewFeatureStr);
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
setAttributes(Function & F,const ArrayRef<Optional<Attribute>> NewAttrs)3515ffd83dbSDimitry Andric void AMDGPUPropagateAttributes::setAttributes(Function &F,
3525ffd83dbSDimitry Andric     const ArrayRef<Optional<Attribute>> NewAttrs) {
3535ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "Set attributes on " << F.getName() << ":\n");
3545ffd83dbSDimitry Andric   for (unsigned I = 0; I < NumAttr; ++I) {
3555ffd83dbSDimitry Andric     F.removeFnAttr(AttributeNames[I]);
3565ffd83dbSDimitry Andric     if (NewAttrs[I]) {
3575ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << '\t' << NewAttrs[I]->getAsString() << '\n');
3585ffd83dbSDimitry Andric       F.addFnAttr(*NewAttrs[I]);
3595ffd83dbSDimitry Andric     }
3605ffd83dbSDimitry Andric   }
3615ffd83dbSDimitry Andric }
3625ffd83dbSDimitry Andric 
3630b57cec5SDimitry Andric std::string
getFeatureString(const FeatureBitset & Features) const3640b57cec5SDimitry Andric AMDGPUPropagateAttributes::getFeatureString(const FeatureBitset &Features) const
3650b57cec5SDimitry Andric {
3660b57cec5SDimitry Andric   std::string Ret;
3670b57cec5SDimitry Andric   for (const SubtargetFeatureKV &KV : AMDGPUFeatureKV) {
3680b57cec5SDimitry Andric     if (Features[KV.Value])
3690b57cec5SDimitry Andric       Ret += (StringRef("+") + KV.Key + ",").str();
3700b57cec5SDimitry Andric     else if (TargetFeatures[KV.Value])
3710b57cec5SDimitry Andric       Ret += (StringRef("-") + KV.Key + ",").str();
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric   Ret.pop_back(); // Remove last comma.
3740b57cec5SDimitry Andric   return Ret;
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
runOnFunction(Function & F)3770b57cec5SDimitry Andric bool AMDGPUPropagateAttributesEarly::runOnFunction(Function &F) {
378af732203SDimitry Andric   if (!TM) {
379af732203SDimitry Andric     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
380af732203SDimitry Andric     if (!TPC)
381af732203SDimitry Andric       return false;
382af732203SDimitry Andric 
383af732203SDimitry Andric     TM = &TPC->getTM<TargetMachine>();
384af732203SDimitry Andric   }
385af732203SDimitry Andric 
386af732203SDimitry Andric   if (!AMDGPU::isEntryFunctionCC(F.getCallingConv()))
3870b57cec5SDimitry Andric     return false;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   return AMDGPUPropagateAttributes(TM, false).process(F);
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric 
runOnModule(Module & M)3920b57cec5SDimitry Andric bool AMDGPUPropagateAttributesLate::runOnModule(Module &M) {
393af732203SDimitry Andric   if (!TM) {
394af732203SDimitry Andric     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
395af732203SDimitry Andric     if (!TPC)
3960b57cec5SDimitry Andric       return false;
3970b57cec5SDimitry Andric 
398af732203SDimitry Andric     TM = &TPC->getTM<TargetMachine>();
399af732203SDimitry Andric   }
400af732203SDimitry Andric 
4010b57cec5SDimitry Andric   return AMDGPUPropagateAttributes(TM, true).process(M);
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric FunctionPass
createAMDGPUPropagateAttributesEarlyPass(const TargetMachine * TM)4050b57cec5SDimitry Andric *llvm::createAMDGPUPropagateAttributesEarlyPass(const TargetMachine *TM) {
4060b57cec5SDimitry Andric   return new AMDGPUPropagateAttributesEarly(TM);
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric ModulePass
createAMDGPUPropagateAttributesLatePass(const TargetMachine * TM)4100b57cec5SDimitry Andric *llvm::createAMDGPUPropagateAttributesLatePass(const TargetMachine *TM) {
4110b57cec5SDimitry Andric   return new AMDGPUPropagateAttributesLate(TM);
4120b57cec5SDimitry Andric }
413af732203SDimitry Andric 
414af732203SDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)415af732203SDimitry Andric AMDGPUPropagateAttributesEarlyPass::run(Function &F,
416af732203SDimitry Andric                                         FunctionAnalysisManager &AM) {
417af732203SDimitry Andric   if (!AMDGPU::isEntryFunctionCC(F.getCallingConv()))
418af732203SDimitry Andric     return PreservedAnalyses::all();
419af732203SDimitry Andric 
420af732203SDimitry Andric   return AMDGPUPropagateAttributes(&TM, false).process(F)
421af732203SDimitry Andric              ? PreservedAnalyses::none()
422af732203SDimitry Andric              : PreservedAnalyses::all();
423af732203SDimitry Andric }
424af732203SDimitry Andric 
425af732203SDimitry Andric PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)426af732203SDimitry Andric AMDGPUPropagateAttributesLatePass::run(Module &M, ModuleAnalysisManager &AM) {
427af732203SDimitry Andric   return AMDGPUPropagateAttributes(&TM, true).process(M)
428af732203SDimitry Andric              ? PreservedAnalyses::none()
429af732203SDimitry Andric              : PreservedAnalyses::all();
430af732203SDimitry Andric }
431