aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJF Bastien <jfb@chromium.org>2013-07-30 16:38:26 -0700
committerJF Bastien <jfb@chromium.org>2013-07-30 16:38:26 -0700
commitf75fd0a9f95109b9cb13a74aad6dcc98c3d5d625 (patch)
tree652c465d76008ef58f5c8d55827050a6f1d875e1 /lib
parent423b3bb89c78e96c59843aa7c6e55d01bde174d1 (diff)
Rewrite ``asm("":::"memory")`` to ``fence seq_cst``
This is often used as a compiler barrier and should "just work" in user code. BUG= https://code.google.com/p/nativeclient/issues/detail?id=2345 R=eliben@chromium.org TEST= (cd ./pnacl/build/llvm_x86_64 && ninja check-all) Review URL: https://codereview.chromium.org/21178002
Diffstat (limited to 'lib')
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt1
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp4
-rw-r--r--lib/Transforms/NaCl/RewriteAsmDirectives.cpp111
3 files changed, 115 insertions, 1 deletions
diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt
index e91d79f184..909cd8c68d 100644
--- a/lib/Transforms/NaCl/CMakeLists.txt
+++ b/lib/Transforms/NaCl/CMakeLists.txt
@@ -20,6 +20,7 @@ add_llvm_library(LLVMNaClTransforms
PromoteIntegers.cpp
ReplacePtrsWithInts.cpp
ResolvePNaClIntrinsics.cpp
+ RewriteAsmDirectives.cpp
RewriteAtomics.cpp
RewriteLLVMIntrinsics.cpp
RewritePNaClLibraryCalls.cpp
diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp
index 189d87f2cb..4f8e0e4f87 100644
--- a/lib/Transforms/NaCl/PNaClABISimplify.cpp
+++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp
@@ -30,8 +30,10 @@ void llvm::PNaClABISimplifyAddPreOptPasses(PassManager &PM) {
// LowerExpect converts Intrinsic::expect into branch weights,
// which can then be removed after BlockPlacement.
PM.add(createLowerExpectIntrinsicPass());
- // Rewrite unsupported intrinsics to simpler constructs.
+ // Rewrite unsupported intrinsics and inline assembly directives to
+ // simpler and portable constructs.
PM.add(createRewriteLLVMIntrinsicsPass());
+ PM.add(createRewriteAsmDirectivesPass());
// LowerInvoke prevents use of C++ exception handling, which is not
// yet supported in the PNaCl ABI.
PM.add(createLowerInvokePass());
diff --git a/lib/Transforms/NaCl/RewriteAsmDirectives.cpp b/lib/Transforms/NaCl/RewriteAsmDirectives.cpp
new file mode 100644
index 0000000000..cb726d2365
--- /dev/null
+++ b/lib/Transforms/NaCl/RewriteAsmDirectives.cpp
@@ -0,0 +1,111 @@
+//===- RewriteAsmDirectives.cpp - Handle Architecture-Independent Assembly-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass rewrites any inline assembly directive which is portable
+// into LLVM bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InstVisitor.h"
+#include "llvm/Pass.h"
+#include <string>
+
+using namespace llvm;
+
+namespace {
+class RewriteAsmDirectives : public FunctionPass {
+public:
+ static char ID; // Pass identification, replacement for typeid
+ RewriteAsmDirectives() : FunctionPass(ID) {
+ initializeRewriteAsmDirectivesPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnFunction(Function &F);
+};
+
+class AsmDirectivesVisitor : public InstVisitor<AsmDirectivesVisitor> {
+public:
+ AsmDirectivesVisitor(Function &F)
+ : F(F), C(F.getParent()->getContext()), ModifiedFunction(false) {}
+ ~AsmDirectivesVisitor() {}
+ bool modifiedFunction() const { return ModifiedFunction; }
+
+ /// Only Call Instructions are ever inline assembly directives.
+ void visitCallInst(CallInst &CI);
+
+private:
+ Function &F;
+ LLVMContext &C;
+ bool ModifiedFunction;
+
+ AsmDirectivesVisitor() LLVM_DELETED_FUNCTION;
+ AsmDirectivesVisitor(const AsmDirectivesVisitor &) LLVM_DELETED_FUNCTION;
+ AsmDirectivesVisitor &operator=(const AsmDirectivesVisitor &) LLVM_DELETED_FUNCTION;
+};
+}
+
+char RewriteAsmDirectives::ID = 0;
+INITIALIZE_PASS(
+ RewriteAsmDirectives, "rewrite-asm-directives",
+ "rewrite portable inline assembly directives into non-asm LLVM IR",
+ false, false)
+
+bool RewriteAsmDirectives::runOnFunction(Function &F) {
+ AsmDirectivesVisitor AV(F);
+ AV.visit(F);
+ return AV.modifiedFunction();
+}
+
+void AsmDirectivesVisitor::visitCallInst(CallInst &CI) {
+ if (!CI.isInlineAsm())
+ return;
+
+ Instruction *Replacement = NULL;
+
+ InlineAsm *IA = cast<InlineAsm>(CI.getCalledValue());
+ std::string AsmStr(IA->getAsmString());
+ std::string ConstraintStr(IA->getConstraintString());
+ Type *T = CI.getType();
+
+ bool isEmptyAsm = AsmStr.empty();
+ // Different triples will encode "touch everything" differently, e.g.:
+ // - le32-unknown-nacl has "~{memory}".
+ // - x86 "~{memory},~{dirflag},~{fpsr},~{flags}".
+ // The following code therefore only searches for memory: this pass
+ // deals with portable assembly, touching anything else than memory in
+ // an empty assembly statement is meaningless.
+ bool touchesMemory = ConstraintStr.find("~{memory}") != std::string::npos;
+
+ if (T->isVoidTy() && IA->hasSideEffects() && isEmptyAsm && touchesMemory) {
+ // asm("":::"memory") => fence seq_cst
+ // This transformation is safe and strictly stronger: the former is
+ // purely a compiler fence, whereas the latter is a compiler fence
+ // as well as a hardware fence which orders all loads and stores on
+ // the current thread of execution.
+ Replacement = new FenceInst(C, SequentiallyConsistent, CrossThread, &CI);
+ }
+
+ if (Replacement) {
+ Replacement->setDebugLoc(CI.getDebugLoc());
+ CI.replaceAllUsesWith(Replacement);
+ CI.eraseFromParent();
+ ModifiedFunction = true;
+ }
+}
+
+namespace llvm {
+FunctionPass *createRewriteAsmDirectivesPass() {
+ return new RewriteAsmDirectives();
+}
+}