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