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