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