Index: lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp |
diff --git a/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp b/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a11dd0f5b096917d1a6278180e780daa23a7adf8 |
--- /dev/null |
+++ b/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp |
@@ -0,0 +1,148 @@ |
+//===- 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() 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) |
+ |
+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); |
+ |
+ return visitUses(FltRoundsRewriter) | visitUses(PrefetchRewriter); |
+} |
+ |
+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(); |
+} |