aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJF Bastien <jfb@chromium.org>2013-07-20 19:35:41 -0700
committerJF Bastien <jfb@chromium.org>2013-07-20 19:35:41 -0700
commit1856bd7d7cb47f7ae32b7c848a8df5c28281e424 (patch)
tree5183147b68bd8c70e2975f794f1cf8e9d6a1dc74
parent58dfde724a201838b40f1314590ec4a1a7f2a601 (diff)
Remove prefetch
Following our discussion in the related bug, prefetch will not be part of our initial stable ABI. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3531 TEST= cd ./pnacl/build/llvm_x86_64; ninja check R=jvoung@chromium.org Review URL: https://codereview.chromium.org/19771015
-rw-r--r--lib/Analysis/NaCl/PNaClABIVerifyModule.cpp1
-rw-r--r--lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp123
-rw-r--r--test/Transforms/NaCl/rewrite-flt-rounds.ll2
-rw-r--r--test/Transforms/NaCl/rewrite-prefetch.ll35
4 files changed, 134 insertions, 27 deletions
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
index a418246bae..2793d2ec96 100644
--- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
+++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
@@ -316,7 +316,6 @@ bool AllowedIntrinsics::isAllowed(const Function *Func) {
case Intrinsic::dbg_value:
return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata;
case Intrinsic::nacl_target_arch: // Used by translator self-build.
- case Intrinsic::prefetch: // TODO(jfb): Use our own data-prefetch intrinsic instead.
return PNaClABIAllowDevIntrinsics;
}
}
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;
}
diff --git a/test/Transforms/NaCl/rewrite-flt-rounds.ll b/test/Transforms/NaCl/rewrite-flt-rounds.ll
index 3c368b8bc3..cb1a7e4a99 100644
--- a/test/Transforms/NaCl/rewrite-flt-rounds.ll
+++ b/test/Transforms/NaCl/rewrite-flt-rounds.ll
@@ -1,6 +1,6 @@
; RUN: opt < %s -rewrite-llvm-intrinsic-calls -S | FileCheck %s
; RUN: opt < %s -rewrite-llvm-intrinsic-calls -S | FileCheck %s -check-prefix=CLEANED
-; Test the RewriteLLVMIntrinsics pass
+; Test the @llvm.flt.rounds part of the RewriteLLVMIntrinsics pass
declare i32 @llvm.flt.rounds()
diff --git a/test/Transforms/NaCl/rewrite-prefetch.ll b/test/Transforms/NaCl/rewrite-prefetch.ll
new file mode 100644
index 0000000000..d498c2012e
--- /dev/null
+++ b/test/Transforms/NaCl/rewrite-prefetch.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -rewrite-llvm-intrinsic-calls -S | FileCheck %s
+; RUN: opt < %s -rewrite-llvm-intrinsic-calls -S | FileCheck %s -check-prefix=CLEANED
+; Test the @llvm.prefetch part of the RewriteLLVMIntrinsics pass
+
+declare void @llvm.prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type)
+
+; No declaration or definition of llvm.prefetch() should remain.
+; CLEANED-NOT: @llvm.prefetch
+
+define void @call_prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type) {
+; CHECK: call_prefetch
+; CHECK-NEXT: ret void
+ call void @llvm.prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type)
+ ret void
+}
+
+; A more complex example with a number of calls in several BBs.
+define void @multiple_calls(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type) {
+; CHECK: multiple_calls
+entryblock:
+; CHECK: entryblock
+; CHECK-NEXT: br
+ call void @llvm.prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type)
+ br label %block1
+block1:
+; CHECK: block1:
+; CHECK-NEXT: br
+ call void @llvm.prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type)
+ br label %exitblock
+exitblock:
+; CHECK: exitblock:
+; CHECK-NEXT: ret void
+ call void @llvm.prefetch(i8 *%ptr, i32 %rw, i32 %locality, i32 %cache_type)
+ ret void
+}