blob: bfe7e0048f3e2c41966326347245e38e01c05a6d [file] [log] [blame]
//===- LowerNonEmIntrinsics - Lower non-emscripten stuff -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Lowers LLVM intrinsics to libc calls where Emscripten needs that. For example,
// if LLVM has llvm.cos.f32 then lower that here to libc cosf, which then will
// get linked in properly. Otherwise, we need to link in those libc components
// after our final codegen, which requires a mechanism for that. We do have such
// a mechanism for the wasm backend, but not for asm.js and asm2wasm (for asm2wasm
// we could use the wasm backend one, but that would not solve things for asm.js
// which we need anyhow; but in theory for asm2wasm we could switch to the wasm
// backend).
//
// It makes sense to run this after optimizations, as the optimizer can do
// things with the intrinsics. However, LTO opts may be done later...
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/NaCl.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/LowerNonEmIntrinsics.h"
using namespace llvm;
#define DEBUG_TYPE "lower-non-em-intrinsics"
namespace {
class LowerNonEmIntrinsics : public ModulePass {
LowerNonEmIntrinsicsPass Impl;
public:
static char ID; // Pass identification
LowerNonEmIntrinsics() : ModulePass(ID) {
initializeLowerNonEmIntrinsicsPass(*PassRegistry::getPassRegistry());
}
bool runOnModule(Module &M) override {
ModuleAnalysisManager MAM;
Impl.run(M, MAM);
return true; // XXX
}
};
} // end anonymous namespace
LowerNonEmIntrinsicsPass::LowerNonEmIntrinsicsPass() {}
PreservedAnalyses LowerNonEmIntrinsicsPass::run(Module &M, ModuleAnalysisManager &AM) {
Type *f32 = Type::getFloatTy(M.getContext());
Type *f64 = Type::getDoubleTy(M.getContext());
// XXX bool Changed = false;
for (auto T : { f32, f64 }) {
for (std::string Name : { "cos", "exp", "log", "pow", "sin", "sqrt" }) {
auto IntrinsicName = std::string("llvm.") + Name + '.' + (T == f32 ? "f32" : "f64");
if (auto* IntrinsicFunc = M.getFunction(IntrinsicName)) {
auto LibcName = std::string(Name) + (T == f32 ? "f" : "");
auto* LibcFunc = M.getFunction(LibcName);
if (!LibcFunc) {
SmallVector<Type*, 2> Types;
Types.push_back(T);
// Almost all of them take a single parameter.
if (Name == "pow") {
Types.push_back(T);
}
auto* FuncType = FunctionType::get(T, Types, false);
LibcFunc = Function::Create(FuncType, GlobalValue::ExternalLinkage, LibcName, &M);
}
IntrinsicFunc->replaceAllUsesWith(LibcFunc);
IntrinsicFunc->eraseFromParent();
// XXX Changed = true;
}
}
}
PreservedAnalyses PA;
return PA;
}
char LowerNonEmIntrinsics::ID = 0;
INITIALIZE_PASS(LowerNonEmIntrinsics, "lower-non-em-intrinsics",
"Lower intrinsics for libc calls for js/emscripten", false, false)
llvm::ModulePass *llvm::createLowerNonEmIntrinsicsPass() {
return new LowerNonEmIntrinsics();
}