blob: 119b85aaa1a442f0d81c91ad7e3f8684b833daa9 [file] [log] [blame]
//===- RewriteLLVMIntrinsics.cpp - Rewrite LLVM intrinsics to other values ===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass replaces calls to LLVM intrinsics that are *not* part of the
// PNaCl stable bitcode ABI into simpler values.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"
#include <string>
using namespace llvm;
namespace {
class RewriteLLVMIntrinsics : public ModulePass {
public:
static char ID;
RewriteLLVMIntrinsics() : ModulePass(ID) {
// This is a module pass because this makes it easier to access uses
// of global intrinsic functions.
initializeRewriteLLVMIntrinsicsPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
/// Rewrite an intrinsic to something different.
class IntrinsicRewriter {
public:
Function *function() const { return F; }
/// Called once per \p Call of the Intrinsic Function.
void rewriteCall(CallInst *Call) { doRewriteCall(Call); }
protected:
IntrinsicRewriter(Module &M, Intrinsic::ID IntrinsicID)
: F(Intrinsic::getDeclaration(&M, IntrinsicID)) {}
virtual ~IntrinsicRewriter() {}
/// This pure virtual method must be defined by implementors, and
/// will be called by rewriteCall.
virtual void doRewriteCall(CallInst *Call) = 0;
Function *F;
private:
IntrinsicRewriter() = delete;
IntrinsicRewriter(const IntrinsicRewriter &) = delete;
IntrinsicRewriter &operator=(const IntrinsicRewriter &) = delete;
};
private:
/// Visit all uses of a Function, rewrite it using the \p Rewriter,
/// and then delete the Call. Later delete the Function from the
/// Module. Returns true if the Module was changed.
bool visitUses(IntrinsicRewriter &Rewriter);
};
/// Rewrite a Call to nothing.
class ToNothing : public RewriteLLVMIntrinsics::IntrinsicRewriter {
public:
ToNothing(Module &M, Intrinsic::ID IntrinsicID)
: IntrinsicRewriter(M, IntrinsicID) {}
virtual ~ToNothing() {}
protected:
virtual void doRewriteCall(CallInst *Call) {
// Nothing to do: the visit does the deletion.
}
};
/// Rewrite a Call to a ConstantInt of the same type.
class ToConstantInt : public RewriteLLVMIntrinsics::IntrinsicRewriter {
public:
ToConstantInt(Module &M, Intrinsic::ID IntrinsicID, uint64_t Value)
: IntrinsicRewriter(M, IntrinsicID), Value(Value),
RetType(function()->getFunctionType()->getReturnType()) {}
virtual ~ToConstantInt() {}
protected:
virtual void doRewriteCall(CallInst *Call) {
Constant *C = ConstantInt::get(RetType, Value);
Call->replaceAllUsesWith(C);
}
private:
uint64_t Value;
Type *RetType;
};
}
char RewriteLLVMIntrinsics::ID = 0;
INITIALIZE_PASS(RewriteLLVMIntrinsics, "rewrite-llvm-intrinsic-calls",
"Rewrite LLVM intrinsic calls to simpler expressions", false,
false)
bool RewriteLLVMIntrinsics::runOnModule(Module &M) {
// Replace all uses of the @llvm.flt.rounds intrinsic with the constant
// "1" (round-to-nearest). Until we add a second intrinsic like
// @llvm.set.flt.round it is impossible to have a rounding mode that is
// not the initial rounding mode (round-to-nearest). We can remove
// this rewrite after adding a set() intrinsic.
ToConstantInt FltRoundsRewriter(M, Intrinsic::flt_rounds, 1);
// Remove all @llvm.prefetch intrinsics.
ToNothing PrefetchRewriter(M, Intrinsic::prefetch);
ToNothing AssumeRewriter(M, Intrinsic::assume);
return visitUses(FltRoundsRewriter) | visitUses(PrefetchRewriter)
| visitUses(AssumeRewriter);
}
bool RewriteLLVMIntrinsics::visitUses(IntrinsicRewriter &Rewriter) {
Function *F = Rewriter.function();
SmallVector<CallInst *, 64> Calls;
for (User *U : F->users()) {
if (CallInst *Call = dyn_cast<CallInst>(U)) {
Calls.push_back(Call);
} else {
// Intrinsics we care about currently don't need to handle this case.
std::string S;
raw_string_ostream OS(S);
OS << "Taking the address of this intrinsic is invalid: " << *U;
report_fatal_error(OS.str());
}
}
for (auto Call : Calls) {
Rewriter.rewriteCall(Call);
Call->eraseFromParent();
}
F->eraseFromParent();
return !Calls.empty();
}
ModulePass *llvm::createRewriteLLVMIntrinsicsPass() {
return new RewriteLLVMIntrinsics();
}