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
26using namespace llvm;
27
28namespace {
29
30class PPCGenScalarMASSEntries : public ModulePass {
31public:
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
51private:
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
63bool PPCGenScalarMASSEntries::isCandidateSafeToLower(const CallInst &CI) const {
64 // skip functions with no scalar or vector FP type (like cosisin)
65 if (!isa<FPMathOperator>(Val: 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
73bool PPCGenScalarMASSEntries::isFiniteCallSafe(const CallInst &CI) const {
74 // skip functions with no scalar or vector FP type (like cosisin)
75 if (!isa<FPMathOperator>(Val: 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.
86bool 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 Name: MASSEntryStr, T: Func.getFunctionType(), AttributeList: Func.getAttributes());
101
102 CI.setCalledFunction(FCache);
103
104 return true;
105}
106
107bool 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(x: 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>(Val: User)) {
129 if (isCandidateSafeToLower(CI: *CI))
130 Changed |= createScalarMASSCall(MASSEntry: Iter->second, CI&: *CI, Func);
131 }
132 }
133
134 return Changed;
135}
136
137char PPCGenScalarMASSEntries::ID = 0;
138
139char &llvm::PPCGenScalarMASSEntriesID = PPCGenScalarMASSEntries::ID;
140
141INITIALIZE_PASS(PPCGenScalarMASSEntries, DEBUG_TYPE,
142 "Generate Scalar MASS entries", false, false)
143
144ModulePass *llvm::createPPCGenScalarMASSEntriesPass() {
145 return new PPCGenScalarMASSEntries();
146}
147