1 //===-- PPCGenScalarMASSEntries.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This transformation converts standard math functions into their
10 // corresponding MASS (scalar) entries for PowerPC targets.
11 // Following are examples of such conversion:
12 //     tanh ---> __xl_tanh_finite
13 // Such lowering is legal under the fast-math option.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "PPC.h"
18 #include "PPCSubtarget.h"
19 #include "PPCTargetMachine.h"
20 #include "llvm/Analysis/TargetTransformInfo.h"
21 #include "llvm/CodeGen/TargetPassConfig.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/Module.h"
24 
25 #define DEBUG_TYPE "ppc-gen-scalar-mass"
26 
27 using namespace llvm;
28 
29 namespace {
30 
31 class PPCGenScalarMASSEntries : public ModulePass {
32 public:
33   static char ID;
34 
35   PPCGenScalarMASSEntries() : ModulePass(ID) {
36     ScalarMASSFuncs = {
37 #define TLI_DEFINE_SCALAR_MASS_FUNCS
38 #include "llvm/Analysis/ScalarFuncs.def"
39     };
40   }
41 
42   bool runOnModule(Module &M) override;
43 
44   StringRef getPassName() const override {
45     return "PPC Generate Scalar MASS Entries";
46   }
47 
48   void getAnalysisUsage(AnalysisUsage &AU) const override {
49     AU.addRequired<TargetTransformInfoWrapperPass>();
50   }
51 
52 private:
53   std::map<StringRef, StringRef> ScalarMASSFuncs;
54   bool isCandidateSafeToLower(const CallInst &CI) const;
55   bool isFiniteCallSafe(const CallInst &CI) const;
56   bool createScalarMASSCall(StringRef MASSEntry, CallInst &CI,
57                             Function &Func) const;
58 };
59 
60 } // namespace
61 
62 // Returns true if 'afn' flag exists on the call instruction with the math
63 // function
64 bool PPCGenScalarMASSEntries::isCandidateSafeToLower(const CallInst &CI) const {
65   // skip functions with no scalar or vector FP type (like cosisin)
66   if (!isa<FPMathOperator>(CI))
67     return false;
68 
69   return CI.hasApproxFunc();
70 }
71 
72 // Returns true if 'nnan', 'ninf' and 'nsz' flags exist on the call instruction
73 // with the math function
74 bool PPCGenScalarMASSEntries::isFiniteCallSafe(const CallInst &CI) const {
75   // skip functions with no scalar or vector FP type (like cosisin)
76   if (!isa<FPMathOperator>(CI))
77     return false;
78 
79   // FIXME: no-errno and trapping-math need to be set for MASS converstion
80   // but they don't have IR representation.
81   return CI.hasNoNaNs() && CI.hasNoInfs() && CI.hasNoSignedZeros();
82 }
83 
84 /// Lowers scalar math functions to scalar MASS functions.
85 ///     e.g.: tanh         --> __xl_tanh_finite or __xl_tanh
86 /// Both function prototype and its callsite is updated during lowering.
87 bool PPCGenScalarMASSEntries::createScalarMASSCall(StringRef MASSEntry,
88                                                    CallInst &CI,
89                                                    Function &Func) const {
90   if (CI.use_empty())
91     return false;
92 
93   Module *M = Func.getParent();
94   assert(M && "Expecting a valid Module");
95 
96   std::string MASSEntryStr = MASSEntry.str();
97   if (isFiniteCallSafe(CI))
98     MASSEntryStr += "_finite";
99 
100   FunctionCallee FCache = M->getOrInsertFunction(
101       MASSEntryStr, Func.getFunctionType(), Func.getAttributes());
102 
103   CI.setCalledFunction(FCache);
104 
105   return true;
106 }
107 
108 bool PPCGenScalarMASSEntries::runOnModule(Module &M) {
109   bool Changed = false;
110 
111   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
112   if (!TPC || skipModule(M))
113     return false;
114 
115   for (Function &Func : M) {
116     if (!Func.isDeclaration())
117       continue;
118 
119     auto Iter = ScalarMASSFuncs.find(Func.getName());
120     if (Iter == ScalarMASSFuncs.end())
121       continue;
122 
123     // The call to createScalarMASSCall() invalidates the iterator over users
124     // upon replacing the users. Precomputing the current list of users allows
125     // us to replace all the call sites.
126     SmallVector<User *, 4> TheUsers;
127     for (auto *User : Func.users())
128       TheUsers.push_back(User);
129 
130     for (auto *User : TheUsers)
131       if (auto *CI = dyn_cast_or_null<CallInst>(User)) {
132         if (isCandidateSafeToLower(*CI))
133           Changed |= createScalarMASSCall(Iter->second, *CI, Func);
134       }
135   }
136 
137   return Changed;
138 }
139 
140 char PPCGenScalarMASSEntries::ID = 0;
141 
142 char &llvm::PPCGenScalarMASSEntriesID = PPCGenScalarMASSEntries::ID;
143 
144 INITIALIZE_PASS(PPCGenScalarMASSEntries, DEBUG_TYPE,
145                 "Generate Scalar MASS entries", false, false)
146 
147 ModulePass *llvm::createPPCGenScalarMASSEntriesPass() {
148   return new PPCGenScalarMASSEntries();
149 }
150