aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp')
-rw-r--r--lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp123
1 files changed, 98 insertions, 25 deletions
diff --git a/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp b/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp
index 17cd2347cc..9b3d3cea51 100644
--- a/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp
+++ b/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp
@@ -12,57 +12,130 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/Twine.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 {
+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:
- 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());
- }
+ 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;
- virtual bool runOnModule(Module &M);
+ Function *F;
+
+ private:
+ IntrinsicRewriter() LLVM_DELETED_FUNCTION;
+ IntrinsicRewriter(const IntrinsicRewriter &) LLVM_DELETED_FUNCTION;
+ IntrinsicRewriter &operator=(
+ const IntrinsicRewriter &) LLVM_DELETED_FUNCTION;
};
+
+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)
+ "Rewrite LLVM intrinsic calls to simpler expressions", false,
+ false)
bool RewriteLLVMIntrinsics::runOnModule(Module &M) {
- bool Changed = false;
+ // 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);
- // Iterate over all uses of the llvm.flt.rounds, and replace it 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.
- Function *FltRounds = Intrinsic::getDeclaration(&M, Intrinsic::flt_rounds);
- Type *RetType = FltRounds->getFunctionType()->getReturnType();
- for (Value::use_iterator UI = FltRounds->use_begin(),
- UE = FltRounds->use_end(); UI != UE;) {
+ // Remove all @llvm.prefetch intrinsics.
+ ToNothing PrefetchRewriter(M, Intrinsic::prefetch);
+
+ return visitUses(FltRoundsRewriter) | visitUses(PrefetchRewriter);
+}
+
+bool RewriteLLVMIntrinsics::visitUses(IntrinsicRewriter &Rewriter) {
+ bool Changed = false;
+ Function *F = Rewriter.function();
+ for (Value::use_iterator UI = F->use_begin(), UE = F->use_end(); UI != UE;) {
Value *Use = *UI++;
if (CallInst *Call = dyn_cast<CallInst>(Use)) {
- Constant *C = ConstantInt::get(RetType, 1);
- Call->replaceAllUsesWith(C);
+ Rewriter.rewriteCall(Call);
Call->eraseFromParent();
Changed = true;
} else {
- report_fatal_error("Taking the address of llvm.flt.rounds is invalid");
+ // 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: " << *Use;
+ report_fatal_error(OS.str());
}
}
- FltRounds->eraseFromParent();
-
+ F->eraseFromParent();
return Changed;
}