forked from OSchip/llvm-project
150 lines
4.5 KiB
C++
150 lines
4.5 KiB
C++
//===-- PPCGenScalarMASSEntries.cpp ---------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This transformation converts standard math functions into their
|
|
// corresponding MASS (scalar) entries for PowerPC targets.
|
|
// Following are examples of such conversion:
|
|
// tanh ---> __xl_tanh_finite
|
|
// Such lowering is legal under the fast-math option.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PPC.h"
|
|
#include "PPCSubtarget.h"
|
|
#include "PPCTargetMachine.h"
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#define DEBUG_TYPE "ppc-gen-scalar-mass"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class PPCGenScalarMASSEntries : public ModulePass {
|
|
public:
|
|
static char ID;
|
|
|
|
PPCGenScalarMASSEntries() : ModulePass(ID) {
|
|
ScalarMASSFuncs = {
|
|
#define TLI_DEFINE_SCALAR_MASS_FUNCS
|
|
#include "llvm/Analysis/ScalarFuncs.def"
|
|
};
|
|
}
|
|
|
|
bool runOnModule(Module &M) override;
|
|
|
|
StringRef getPassName() const override {
|
|
return "PPC Generate Scalar MASS Entries";
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
}
|
|
|
|
private:
|
|
std::map<StringRef, StringRef> ScalarMASSFuncs;
|
|
bool isCandidateSafeToLower(const CallInst &CI) const;
|
|
bool isFiniteCallSafe(const CallInst &CI) const;
|
|
bool createScalarMASSCall(StringRef MASSEntry, CallInst &CI,
|
|
Function &Func) const;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
// Returns true if 'afn' flag exists on the call instruction with the math
|
|
// function
|
|
bool PPCGenScalarMASSEntries::isCandidateSafeToLower(const CallInst &CI) const {
|
|
// skip functions with no scalar or vector FP type (like cosisin)
|
|
if (!isa<FPMathOperator>(CI))
|
|
return false;
|
|
|
|
return CI.hasApproxFunc();
|
|
}
|
|
|
|
// Returns true if 'nnan', 'ninf' and 'nsz' flags exist on the call instruction
|
|
// with the math function
|
|
bool PPCGenScalarMASSEntries::isFiniteCallSafe(const CallInst &CI) const {
|
|
// skip functions with no scalar or vector FP type (like cosisin)
|
|
if (!isa<FPMathOperator>(CI))
|
|
return false;
|
|
|
|
// FIXME: no-errno and trapping-math need to be set for MASS converstion
|
|
// but they don't have IR representation.
|
|
return CI.hasNoNaNs() && CI.hasNoInfs() && CI.hasNoSignedZeros();
|
|
}
|
|
|
|
/// Lowers scalar math functions to scalar MASS functions.
|
|
/// e.g.: tanh --> __xl_tanh_finite or __xl_tanh
|
|
/// Both function prototype and its callsite is updated during lowering.
|
|
bool PPCGenScalarMASSEntries::createScalarMASSCall(StringRef MASSEntry,
|
|
CallInst &CI,
|
|
Function &Func) const {
|
|
if (CI.use_empty())
|
|
return false;
|
|
|
|
Module *M = Func.getParent();
|
|
assert(M && "Expecting a valid Module");
|
|
|
|
std::string MASSEntryStr = MASSEntry.str();
|
|
if (isFiniteCallSafe(CI))
|
|
MASSEntryStr += "_finite";
|
|
|
|
FunctionCallee FCache = M->getOrInsertFunction(
|
|
MASSEntryStr, Func.getFunctionType(), Func.getAttributes());
|
|
|
|
CI.setCalledFunction(FCache);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PPCGenScalarMASSEntries::runOnModule(Module &M) {
|
|
bool Changed = false;
|
|
|
|
auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
|
|
if (!TPC || skipModule(M))
|
|
return false;
|
|
|
|
for (Function &Func : M) {
|
|
if (!Func.isDeclaration())
|
|
continue;
|
|
|
|
auto Iter = ScalarMASSFuncs.find(Func.getName());
|
|
if (Iter == ScalarMASSFuncs.end())
|
|
continue;
|
|
|
|
// The call to createScalarMASSCall() invalidates the iterator over users
|
|
// upon replacing the users. Precomputing the current list of users allows
|
|
// us to replace all the call sites.
|
|
SmallVector<User *, 4> TheUsers;
|
|
for (auto *User : Func.users())
|
|
TheUsers.push_back(User);
|
|
|
|
for (auto *User : TheUsers)
|
|
if (auto *CI = dyn_cast_or_null<CallInst>(User)) {
|
|
if (isCandidateSafeToLower(*CI))
|
|
Changed |= createScalarMASSCall(Iter->second, *CI, Func);
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
char PPCGenScalarMASSEntries::ID = 0;
|
|
|
|
char &llvm::PPCGenScalarMASSEntriesID = PPCGenScalarMASSEntries::ID;
|
|
|
|
INITIALIZE_PASS(PPCGenScalarMASSEntries, DEBUG_TYPE,
|
|
"Generate Scalar MASS entries", false, false)
|
|
|
|
ModulePass *llvm::createPPCGenScalarMASSEntriesPass() {
|
|
return new PPCGenScalarMASSEntries();
|
|
}
|