diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index 9703437..725ba7d 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -124,6 +124,20 @@ void initializeEarlyCSELegacyPassPass(PassRegistry &);
 void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry &);
 void initializeEarlyIfConverterPass(PassRegistry&);
 void initializeEdgeBundlesPass(PassRegistry&);
+void initializeExpandPostRAPass(PassRegistry&);
+void initializeAAResultsWrapperPassPass(PassRegistry &);
+void initializeFencesPREPass(PassRegistry &);
+void initializeGCOVProfilerPass(PassRegistry&);
+void initializePGOInstrumentationGenPass(PassRegistry&);
+void initializePGOInstrumentationUsePass(PassRegistry&);
+void initializePGOIndirectCallPromotionPass(PassRegistry&);
+void initializeInstrProfilingLegacyPassPass(PassRegistry &);
+void initializeAddressSanitizerPass(PassRegistry&);
+void initializeAddressSanitizerModulePass(PassRegistry&);
+void initializeMemorySanitizerPass(PassRegistry&);
+void initializeThreadSanitizerPass(PassRegistry&);
+void initializeSanitizerCoverageModulePass(PassRegistry&);
+void initializeDataFlowSanitizerPass(PassRegistry&);
 void initializeEfficiencySanitizerPass(PassRegistry&);
 void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry &);
 void initializeGVNHoistLegacyPassPass(PassRegistry &);
diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h
index c2910c7..548f057 100644
--- a/include/llvm/LinkAllPasses.h
+++ b/include/llvm/LinkAllPasses.h
@@ -201,6 +201,7 @@ namespace {
       (void) llvm::createMemDerefPrinter();
       (void) llvm::createFloat2IntPass();
       (void) llvm::createEliminateAvailableExternallyPass();
+      (void) llvm::createFencesPREPass();
 
       (void)new llvm::IntervalPartition();
       (void)new llvm::ScalarEvolutionWrapperPass();
diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h
index f67331e..7f5373d 100644
--- a/include/llvm/Transforms/Scalar.h
+++ b/include/llvm/Transforms/Scalar.h
@@ -16,6 +16,8 @@
 #define LLVM_TRANSFORMS_SCALAR_H
 
 #include <functional>
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/Transforms/Scalar/FencesPRE.h"
 
 namespace llvm {
 
@@ -25,10 +27,28 @@ class FunctionPass;
 class ModulePass;
 class Pass;
 class GetElementPtrInst;
+class Instruction;
+class Pass;
 class PassInfo;
 class TerminatorInst;
 class TargetLowering;
 class TargetMachine;
+class Value;
+
+//===----------------------------------------------------------------------===//
+//
+// FencesPRE - Elimination of target-specific fences based on a PRE algorithm
+//
+FunctionPass *createFencesPREPass(
+    std::function<bool(Instruction &)> IsWantedFence =
+        [](Instruction &I) { return false; },
+    std::function<void(Instruction &)> InsertFenceBefore =
+        [](Instruction &I) { return; },
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationUpwards =
+        [](const Instruction &I) { return FencesPREOperation::Stop; },
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationDownwards =
+        [](const Instruction &I) { return FencesPREOperation::Stop; });
+extern char &FencesPREID;
 
 //===----------------------------------------------------------------------===//
 //
diff --git a/include/llvm/Transforms/Scalar/FencesPRE.h b/include/llvm/Transforms/Scalar/FencesPRE.h
new file mode 100644
index 0000000..b6f5350
--- /dev/null
+++ b/include/llvm/Transforms/Scalar/FencesPRE.h
@@ -0,0 +1,27 @@
+//===- FencesPRE.h - Fence Elimination  --------------------------*- C++ -*===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file 
+/// This file provides the interface to the fence elimination pass.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_FENCESPRE_H
+#define LLVM_TRANSFORMS_SCALAR_FENCESPRE_H
+
+namespace llvm {
+
+enum class FencesPREOperation {
+  Stop, // Stop and connect to either the source or the sink depending on
+	// whether we are going up or down
+  Drop, // Stop and don't connect to anything
+  Continue, // Keep going further
+};
+
+}
+
+#endif
diff --git a/lib/CodeGen/AtomicExpandPass.cpp b/lib/CodeGen/AtomicExpandPass.cpp
index bf5cf10..e7221b4 100644
--- a/lib/CodeGen/AtomicExpandPass.cpp
+++ b/lib/CodeGen/AtomicExpandPass.cpp
@@ -29,10 +29,29 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
 
+#include <iostream>
+
 using namespace llvm;
 
 #define DEBUG_TYPE "atomic-expand"
 
+static cl::opt<bool> AddMFenceBeforeAtomicLoads(
+    "add-mfence-before-atomic-loads", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Add seq_cst fences in lots of places for benching FencesPRE"));
+static cl::opt<bool> AddMFenceAfterAtomicStores(
+    "add-mfence-after-atomic-stores", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Add seq_cst fences in lots of places for benching FencesPRE"));
+static cl::opt<bool> MakeAllAccessesSeqCst(
+    "make-all-accesses-seq-cst", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Make all accesses seq_cst for benching FencesPRE"));
+static cl::opt<bool> MakeAllAtomicAccessesSeqCst(
+    "make-all-atomic-accesses-seq-cst", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Make all atomic accesses seq_cst for benching FencesPRE"));
+
 namespace {
   class AtomicExpand: public FunctionPass {
     const TargetMachine *TM;
@@ -173,21 +192,36 @@ bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) {
 } // end anonymous namespace
 
 bool AtomicExpand::runOnFunction(Function &F) {
+  // std::cerr << "runOnFunction" << std::endl;
   if (!TM || !TM->getSubtargetImpl(F)->enableAtomicExpand())
     return false;
+  // std::cerr << "still running on function" << std::endl;
   TLI = TM->getSubtargetImpl(F)->getTargetLowering();
 
   SmallVector<Instruction *, 1> AtomicInsts;
 
+  bool MadeChange = false;
   // Changing control-flow while iterating through it is a bad idea, so gather a
   // list of all atomic instructions before we start.
   for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
     Instruction *I = &*II;
+    if (MakeAllAccessesSeqCst || (MakeAllAtomicAccessesSeqCst && I->isAtomic())) {
+      // std::cerr << "Making accesses seq_cst" << std::endl;
+      auto LI = dyn_cast<LoadInst>(I);
+      auto SI = dyn_cast<StoreInst>(I);
+      if (LI && getAtomicOpSize(LI) > 1) {
+	LI->setOrdering(AtomicOrdering::SequentiallyConsistent);
+	MadeChange = true;
+      }
+      else if (SI && getAtomicOpSize(SI) > 1) {
+	SI->setOrdering(AtomicOrdering::SequentiallyConsistent);
+	MadeChange = true;
+      }
+    }
     if (I->isAtomic() && !isa<FenceInst>(I))
       AtomicInsts.push_back(I);
   }
 
-  bool MadeChange = false;
   for (auto I : AtomicInsts) {
     auto LI = dyn_cast<LoadInst>(I);
     auto SI = dyn_cast<StoreInst>(I);
@@ -195,6 +229,21 @@ bool AtomicExpand::runOnFunction(Function &F) {
     auto CASI = dyn_cast<AtomicCmpXchgInst>(I);
     assert((LI || SI || RMWI || CASI) && "Unknown atomic instruction");
 
+    if (AddMFenceAfterAtomicStores && SI) {
+      IRBuilder<> Builder(I);
+      Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+      Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::x86_sse2_mfence);
+      auto TrailingFence = Builder.CreateCall(Fence, {});
+      TrailingFence->removeFromParent();
+      TrailingFence->insertAfter(I);
+    }
+    if (AddMFenceBeforeAtomicLoads && LI) {
+      IRBuilder<> Builder(I);
+      Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+      Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::x86_sse2_mfence);
+      Builder.CreateCall(Fence, {});
+    }
+
     // If the Size/Alignment is not supported, replace with a libcall.
     if (LI) {
       if (!atomicSizeSupported(TLI, LI)) {
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 4ef882a..050bd31 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -18,6 +18,7 @@
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/Support/CommandLine.h"
@@ -369,6 +370,33 @@ void ARMPassConfig::addIRPasses() {
   else
     addPass(createAtomicExpandPass(TM));
 
+  // if (TM->getOptLevel() == CodeGenOpt::Aggressive) {
+  if (true) {
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationDmbIsh =
+      [](const Instruction &I) {
+	if (I.mayReadOrWriteMemory() || isa<ReturnInst>(I)) {
+	  return FencesPREOperation::Stop;
+	} else {
+	  return FencesPREOperation::Continue;
+	}
+      };
+    addPass(createFencesPREPass(
+	[](Instruction &I) {
+		auto FI = dyn_cast<IntrinsicInst>(&I);
+		IRBuilder<> Builder(&I);
+		if (!FI) return false;
+		if (FI->getIntrinsicID() != Intrinsic::arm_dmb) return false;
+		return FI->getArgOperand(0) == Builder.getInt32(ARM_MB::ISH);},
+	[](Instruction &I) {
+		IRBuilder<> Builder(&I);
+  		Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+		Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::arm_dmb);
+		Builder.CreateCall(Fence, {Builder.getInt32(ARM_MB::ISH)});},
+        /*ChooseOperationUpwards=*/ChooseOperationDmbIsh,
+        /*ChooseOperationDownwards=*/ChooseOperationDmbIsh
+        ));
+  }
+
   // Cmpxchg instructions are often used with a subsequent comparison to
   // determine whether it succeeded. We can exploit existing control-flow in
   // ldrex/strex loops to simplify this, but it needs tidying up.
@@ -459,8 +487,8 @@ void ARMPassConfig::addPreEmitPass() {
   }));
 
   // Don't optimize barriers at -O0.
-  if (getOptLevel() != CodeGenOpt::None)
-    addPass(createARMOptimizeBarriersPass());
+  // if (getOptLevel() != CodeGenOpt::None)
+  //  addPass(createARMOptimizeBarriersPass());
 
   addPass(createARMConstantIslandPass());
 }
diff --git a/lib/Target/PowerPC/PPCTargetMachine.cpp b/lib/Target/PowerPC/PPCTargetMachine.cpp
index 81d125f..779089c 100644
--- a/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -18,13 +18,17 @@
 #include "llvm/CodeGen/LiveVariables.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/Transforms/Scalar.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Scalar/FencesPRE.h"
 #include "llvm/Transforms/Scalar.h"
 using namespace llvm;
 
@@ -316,19 +320,82 @@ void PPCPassConfig::addIRPasses() {
   if (UsePrefetching)
     addPass(createLoopDataPrefetchPass());
 
-  if (TM->getOptLevel() >= CodeGenOpt::Default && EnableGEPOpt) {
-    // Call SeparateConstOffsetFromGEP pass to extract constants within indices
-    // and lower a GEP with multiple indices to either arithmetic operations or
-    // multiple GEPs with single index.
-    addPass(createSeparateConstOffsetFromGEPPass(TM, true));
-    // Call EarlyCSE pass to find and remove subexpressions in the lowered
-    // result.
-    addPass(createEarlyCSEPass());
-    // Do loop invariant code motion in case part of the lowered result is
-    // invariant.
-    addPass(createLICMPass());
+  // if (TM->getOptLevel() >= CodeGenOpt::Default) {
+  if (true) {
+    if (EnableGEPOpt) {
+      // Call SeparateConstOffsetFromGEP pass to extract constants within indices
+      // and lower a GEP with multiple indices to either arithmetic operations or
+      // multiple GEPs with single index.
+      addPass(createSeparateConstOffsetFromGEPPass(TM, true));
+      // Call EarlyCSE pass to find and remove subexpressions in the lowered
+      // result.
+      addPass(createEarlyCSEPass());
+      // Do loop invariant code motion in case part of the lowered result is
+      // invariant.
+      addPass(createLICMPass());
+    }
+    
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationSync =
+      [](const Instruction &I) {
+	if (!I.mayReadOrWriteMemory()) {
+	  if (isa<ReturnInst>(I))
+	    return FencesPREOperation::Stop;
+	  return FencesPREOperation::Continue;
+	}
+        if (auto FI = dyn_cast<IntrinsicInst>(&I)) {
+          if (FI->getIntrinsicID() == Intrinsic::ppc_lwsync)
+	    return FencesPREOperation::Continue;
+	}
+	return FencesPREOperation::Stop;
+      };
+  
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationLwSync =
+      [](const Instruction &I) {
+	if (!I.mayReadOrWriteMemory()) {
+	  if (isa<ReturnInst>(I))
+	    return FencesPREOperation::Stop;
+	  return FencesPREOperation::Continue;
+	}
+        if (auto FI = dyn_cast<IntrinsicInst>(&I)) {
+          if (FI->getIntrinsicID() == Intrinsic::ppc_sync)
+	    return FencesPREOperation::Drop;
+	}
+	return FencesPREOperation::Stop;
+      };
+      
+    // We first try to eliminate redundant hwsync instructions, ignoring
+    // lwsyncs.
+    addPass(createFencesPREPass(
+	[](Instruction &I) {
+		auto FI = dyn_cast<IntrinsicInst>(&I);
+		return FI && FI->getIntrinsicID() == Intrinsic::ppc_sync;},
+	[](Instruction &I) {
+		IRBuilder<> Builder(&I);
+  		Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+		Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::ppc_sync);
+		Builder.CreateCall(Fence, {});},
+        /*ChooseOperationUpwards=*/ChooseOperationSync,
+        /*ChooseOperationDownwards=*/ChooseOperationSync
+        ));
+    // Then we eliminate redundant lwsyncs, taking into account the hwsyncs.
+    addPass(createFencesPREPass(
+	[](Instruction &I) {
+		auto FI = dyn_cast<IntrinsicInst>(&I);
+		return FI && FI->getIntrinsicID() == Intrinsic::ppc_lwsync;},
+	[](Instruction &I) {
+		IRBuilder<> Builder(&I);
+  		Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+		Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::ppc_lwsync);
+		Builder.CreateCall(Fence, {});},
+        /*ChooseOperationUpwards=*/ChooseOperationLwSync,
+        /*ChooseOperationDownwards=*/ChooseOperationLwSync
+        ));
+    // These two passes require that critical edges be split. So we should
+    // cleanup the CFG afterwards.
+    // FIXME: breaks a bunch of brittle tests
+    // addPass(createCFGSimplificationPass());
   }
-
+      
   TargetPassConfig::addIRPasses();
 }
 
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
index 773438d..9f20f74 100644
--- a/lib/Target/X86/X86TargetMachine.cpp
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -18,11 +18,15 @@
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/FencesPRE.h"
 using namespace llvm;
 
 static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",
@@ -268,6 +272,41 @@ TargetPassConfig *X86TargetMachine::createPassConfig(PassManagerBase &PM) {
 void X86PassConfig::addIRPasses() {
   addPass(createAtomicExpandPass(&getX86TargetMachine()));
 
+  //if (TM->getOptLevel() == CodeGenOpt::Aggressive) {
+  if (true) {
+    addPass(createFencesPREPass(
+	[](Instruction &I) {
+			// std::cerr << "isWantedFence: "; I.dump();
+		auto *FI = dyn_cast<IntrinsicInst>(&I);
+		auto *FI2 = dyn_cast<FenceInst>(&I);
+		return (FI && FI->getIntrinsicID() == Intrinsic::x86_sse2_mfence)
+			|| (FI2 && FI2->getOrdering() == AtomicOrdering::SequentiallyConsistent);},
+	[](Instruction &I) {
+		IRBuilder<> Builder(&I);
+  		Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  		Function *Fence = Intrinsic::getDeclaration(M, Intrinsic::x86_sse2_mfence);
+  		Builder.CreateCall(Fence, {});},
+	/*ChooseOperationUpwards=*/[](const Instruction &I) {
+	  if (!I.mayWriteToMemory() || isa<LoadInst>(I)) {
+	    return FencesPREOperation::Continue;
+	  }
+	  if (isa<AtomicRMWInst>(&I) || isa<AtomicCmpXchgInst>(&I)) {
+            return FencesPREOperation::Drop;
+	  }
+	  return FencesPREOperation::Stop;
+	},
+	/*ChooseOperationDownwards=*/[](const Instruction &I) {
+          if (isa<AtomicRMWInst>(&I) || isa<AtomicCmpXchgInst>(&I)) {
+            return FencesPREOperation::Drop;
+	  } else if (isa<ReturnInst>(I) || (I.mayReadFromMemory() && !isa<StoreInst>(I))) {
+            return FencesPREOperation::Stop;
+	  } else {
+	    return FencesPREOperation::Continue;
+	  }
+	}));
+  }
+  
+
   TargetPassConfig::addIRPasses();
 
   if (TM->getOptLevel() != CodeGenOpt::None)
diff --git a/lib/Transforms/Scalar/CMakeLists.txt b/lib/Transforms/Scalar/CMakeLists.txt
index 9f04344..8b725ce 100644
--- a/lib/Transforms/Scalar/CMakeLists.txt
+++ b/lib/Transforms/Scalar/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_library(LLVMScalarOpts
   DCE.cpp
   DeadStoreElimination.cpp
   EarlyCSE.cpp
+  FencesPRE.cpp
   FlattenCFGPass.cpp
   Float2Int.cpp
   GuardWidening.cpp
diff --git a/lib/Transforms/Scalar/FencesPRE.cpp b/lib/Transforms/Scalar/FencesPRE.cpp
new file mode 100644
index 0000000..417b528
--- /dev/null
+++ b/lib/Transforms/Scalar/FencesPRE.cpp
@@ -0,0 +1,745 @@
+//===- FencesPRE.cpp - Fence Elimination Implementation -=====================//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass eliminates target-specific fence intrinsics that are redundant, or
+// partially redundant if it can introduce new fences to make them fully
+// redundant.
+//
+// The algorithm is based on the following PRE paper, adapted to work on fences:
+// Bernhard Scholz, R. Nigel Horspool, Jens Knoop:
+//     Optimizing for space and time usage with speculative partial redundancy
+//     elimination.
+// LCTES 2004: 221-230
+//
+// The general idea is to build a graph based on the CFG, with a node for each
+// instruction that may affect memory, and a node for each join/split in the
+// CFG, label this graph with the cost per edge of having a fence on that edge
+// (currently using BlockFrequencyInfo). Then each memory-affecting instruction
+// immediately before a fence is marked as a source, each one immediately after
+// a fence is marked as a sink, and a min-cut provides us a minimum-cost set of
+// fences that provide the same ordering guarantees.
+// There are a few subtleties: for example some nodes must be duplicated to
+// prevent them from being both a source and a sink; and the graph is only
+// built around the fences (to avoid the cost of allocating a potentially huge
+// graph).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DOTGraphTraits.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/FencesPRE.h"
+#include <iostream>
+#include <limits>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "fences-pre"
+
+STATISTIC(NumFencesDetected, "Number of fences before FencesPRE");
+STATISTIC(NumFencesInserted, "Number of fences added by FencesPRE");
+STATISTIC(NumFencesDeleted, "Number of fences erased by FencesPRE");
+
+static cl::opt<bool> ViewFencesPREFlowGraph(
+    "view-fences-pre-flow-graph", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Show a representation in dot of the flowgraph used by the fences-pre "
+        "pass"));
+static cl::opt<bool> ConservativeFencesPRE(
+    "conservative-fences-pre", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Make the fences-pre pass conservative"));
+static cl::opt<bool> DisableFencesPRE (
+    "disable-fences-pre", cl::Hidden, cl::init(false),
+    cl::desc("Disable the fences-pre pass"));
+
+namespace llvm {
+// signed so that we can also represent flow.
+// Capacity of edges is (BlockFrequency >> 2) + 1
+// (shifted to fit in 63 bits, +1 because adding a fence increases code size,
+// even in a block that is never executed).
+typedef int64_t Capacity;
+typedef uint32_t Height;
+
+struct FlowGraphNode {
+  Instruction *I;
+  // nullptr unless there is exactly one edge leading to this node, and a
+  // fence exist on this edge. Used to keep existing fences when possible,
+  // instead of erasing them and inserting a new one at the same spot.
+  Instruction *FenceBeforeIt;
+  Capacity Excess;
+  llvm::Height Height;
+  // This bit is used in the algorithm at the end to extract the min-cut
+  // from the max-flow.
+  bool Mark;
+  std::vector<std::pair<FlowGraphNode *, Capacity> > Succs;
+  std::vector<std::pair<FlowGraphNode *, Capacity> >::iterator Next;
+  FlowGraphNode() = delete;
+  FlowGraphNode(Instruction *Inst)
+      : I(Inst),
+        FenceBeforeIt(nullptr),
+        Excess(0),
+        Height(0),
+        Mark(false),
+        Succs(),
+        Next(Succs.begin()) {}
+};
+
+typedef std::pair<FlowGraphNode *, FlowGraphNode *> Edge;
+typedef DenseMap<Instruction *, std::unique_ptr<FlowGraphNode> > FlowGraph;
+typedef SmallPtrSetImpl<FlowGraphNode *> NodeSubset;
+typedef SmallVectorImpl<Edge> Cut;
+typedef DenseMap<Edge, Capacity> Flow;
+typedef std::vector<std::vector<FlowGraphNode *> > Buckets;
+
+struct FlowGraphViewer {
+  const FlowGraph *InstToNodeMap;
+  const NodeSubset *Sources;
+  const NodeSubset *Sinks;
+  const Flow *F;
+  FlowGraphViewer(const FlowGraph *FG, const NodeSubset *S, const NodeSubset *T,
+                  const Flow *Fl)
+      : InstToNodeMap(FG), Sources(S), Sinks(T), F(Fl) {}
+};
+
+class FencesPRE : public FunctionPass {
+ public:
+  static char ID;
+  explicit FencesPRE(
+	    std::function<bool(Instruction &)> IsWantedFence =
+		[](Instruction &I) { return false; },
+	    std::function<void(Instruction &)> InsertFenceBefore =
+		[](Instruction &I) { return; },
+            std::function<FencesPREOperation(const Instruction &)> ChooseOperationUpwards =
+                [](const Instruction &I) { return FencesPREOperation::Stop; },
+            std::function<FencesPREOperation(const Instruction &)> ChooseOperationDownwards =
+                [](const Instruction &I) { return FencesPREOperation::Stop; })
+      : FunctionPass(ID),
+        isWantedFence(IsWantedFence),
+	insertFenceBefore(InsertFenceBefore),
+	chooseOperationUpwards(ChooseOperationUpwards),
+	chooseOperationDownwards(ChooseOperationDownwards) {
+    initializeFencesPREPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    AU.addRequiredID(BreakCriticalEdgesID);
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
+  }
+
+ private:
+  std::function<bool(Instruction &)> isWantedFence;
+  std::function<void(Instruction &)> insertFenceBefore;
+  std::function<FencesPREOperation(const Instruction &)> chooseOperationUpwards;
+  std::function<FencesPREOperation(const Instruction &)> chooseOperationDownwards;
+  BlockFrequencyInfo *BFI;
+
+  FlowGraphNode *makeGraphUpwards(const Instruction &FI, Instruction &Root,
+                                  FlowGraph &NodeBeforeInsts, FlowGraph &NodeAfterInsts,
+                                  NodeSubset &Sources) const;
+  FlowGraphNode *makeGraphDownwards(const Instruction &FI, Instruction &Root,
+                                    FlowGraph &NodeBeforeInsts, FlowGraph &NodeAfterInsts,
+                                    NodeSubset &Sources) const;
+  void findCut(const FlowGraph &NodeBeforeInsts, const FlowGraph &NodeAfterInsts,
+               const NodeSubset &Sources, const NodeSubset &Sinks, Cut &Cut) const;
+  FlowGraphNode *getNode(FlowGraph &FlowGraph, Instruction &I) const;
+  void addEdge(FlowGraphNode *N1, FlowGraphNode *N2) const;
+  Capacity getResidualCapacity(Flow &Flow, Capacity C, FlowGraphNode &U,
+                               FlowGraphNode &V) const;
+  bool push(Buckets &B, Flow &Flow, const NodeSubset &S, const NodeSubset &T,
+            Capacity C, FlowGraphNode &U, FlowGraphNode &V) const;
+  void relabel(Flow &Flow, FlowGraphNode &U) const;
+  Height discharge(Buckets &B, Flow &Flow, const NodeSubset &S,
+                   const NodeSubset &T, FlowGraphNode &U) const;
+  void markNode(Flow &Flow, Cut &Cut, FlowGraphNode &U) const;
+};
+}
+
+char FencesPRE::ID = 0;
+char &llvm::FencesPREID = FencesPRE::ID;
+INITIALIZE_PASS_BEGIN(FencesPRE, "fences-pre",
+                      "Partial redundancy elimination for fences", false, false)
+INITIALIZE_PASS_DEPENDENCY(BreakCriticalEdges)
+INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
+INITIALIZE_PASS_END(FencesPRE, "fences-pre",
+                    "Partial redundancy elimination for fences", false, false)
+
+/*
+static RegisterPass<FencesPRE> X("fences-pre", "Eliminate redundant fences",
+                             false /* Only looks at CFG /,
+                             false /* Analysis Pass /);
+*/
+
+namespace llvm {
+FunctionPass *createFencesPREPass(
+    std::function<bool(Instruction &)> IsWantedFence,
+    std::function<void(Instruction &)> InsertFenceBefore,
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationUpwards,
+    std::function<FencesPREOperation(const Instruction &)> ChooseOperationDownwards) {
+  return new FencesPRE(IsWantedFence, InsertFenceBefore, ChooseOperationUpwards, ChooseOperationDownwards);
+}
+}
+
+bool FencesPRE::runOnFunction(Function &F) {
+  BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+  DEBUG(dbgs() << "runOnFunction\n");
+
+  // unique_ptr to free the nodes when this function exits.
+  FlowGraph NodeBeforeInsts;
+  FlowGraph NodeAfterInsts;
+  SmallPtrSet<FlowGraphNode *, 4> Sources;
+  SmallPtrSet<FlowGraphNode *, 4> Sinks;
+  SmallVector<Edge, 4> Cut;
+  SmallPtrSet<Instruction *, 8> Fences;
+  int LocalNumFencesDetected = 0, LocalNumFencesInserted = 0, LocalNumFencesDeleted = 0;
+
+  for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
+    Instruction *I = &*II;
+    if (isWantedFence(*I)) {
+      Fences.insert(I);
+      ++LocalNumFencesDetected;
+      FlowGraphNode *UpNode = makeGraphUpwards(*I, *I, NodeBeforeInsts, NodeAfterInsts, Sources);
+      FlowGraphNode *DownNode = makeGraphDownwards(*I, *I, NodeBeforeInsts, NodeAfterInsts, Sinks);
+      // These nodes can be null if there is a stronger fence just
+      // before/after this one
+      if (UpNode && DownNode) {
+        DownNode->FenceBeforeIt = I;
+        addEdge(UpNode, DownNode);
+      }
+    }
+  }
+  if (Fences.empty()) return false;
+
+  DEBUG(dbgs() << "Sources:\n"; for (auto S
+                                     : Sources) {
+    dbgs() << "\t" << S << " : ";
+    S->I->dump();
+  });
+  DEBUG(dbgs() << "Sinks:\n"; for (auto T
+                                   : Sinks) {
+    dbgs() << "\t" << T << " : ";
+    T->I->dump();
+  });
+
+  if (DisableFencesPRE) {
+	std::cout << "FencesPRE(disabled): " << LocalNumFencesDetected << " detected" << std::endl;
+	return false;
+  }
+
+  findCut(NodeBeforeInsts, NodeAfterInsts, Sources, Sinks, Cut);
+
+  // We want fences on all the edges in the cut and nowhere else.
+  // For statistics/debugging, we don't want to count the fences already on
+  // the cut as deleted and added back. So for every edge in the cut, we
+  // add a fence if there is none, or mark one on the edge for
+  // preservation if there are some. Then we delete every fence not marked
+  // for preservation. Being "marked for preservation" in this context is
+  // just being removed from the 'Fences' set.
+  for (auto NPair : Cut) {
+    DEBUG(dbgs() << "Pair in the cut:" << NPair.first << " - " << NPair.second
+                 << "\n";
+          dbgs() << "\t"; NPair.first->I->dump(); dbgs() << "\t";
+          NPair.second->I->dump());
+    assert(NPair.first->I->getParent() == NPair.second->I->getParent());
+    // If a fence is already there, just mark it as not for deletion.
+    Instruction *FenceBetweenNPair = NPair.second->FenceBeforeIt;
+    if (FenceBetweenNPair != nullptr) {
+      DEBUG(dbgs() << "preserving fence " << FenceBetweenNPair << "\n");
+      Fences.erase(FenceBetweenNPair);
+      continue;
+    }
+    // Otherwise, insert one.
+    insertFenceBefore(*(NPair.second->I));
+    ++LocalNumFencesInserted;
+  }
+  // And then erase any fence that is still marked for deletion.
+  for (auto FI : Fences) {
+    FI->eraseFromParent();
+    ++LocalNumFencesDeleted;
+  }
+
+  if (LocalNumFencesDetected)
+    std::cout << "FencesPRE: " << LocalNumFencesDetected << " detected / "
+	<< LocalNumFencesDeleted << " deleted / "
+	<< LocalNumFencesInserted << " inserted / "
+	<< LocalNumFencesDetected + LocalNumFencesInserted - LocalNumFencesDeleted
+	<< " remaining" << std::endl;
+  NumFencesDetected += LocalNumFencesDetected;
+  NumFencesDeleted += LocalNumFencesDeleted;
+  NumFencesInserted += LocalNumFencesInserted;
+
+  return (LocalNumFencesDeleted || LocalNumFencesInserted);
+}
+
+void FencesPRE::addEdge(FlowGraphNode *N1, FlowGraphNode *N2) const {
+  if (N1 == nullptr || N2 == nullptr) return;
+
+  auto BB1 = N1->I->getParent(), BB2 = N2->I->getParent();
+  Capacity Capacity;
+  if (BB1 != BB2)
+    Capacity = std::numeric_limits<llvm::Capacity>::max();
+  // Plus one, because it should never be 0, because of code size, inserting a
+  // fence is never completely free, even if the code is only very rarely
+  // executed
+  else
+    Capacity = (BFI->getBlockFreq(BB1).getFrequency() >> 2) + 1;
+
+  N1->Succs.push_back(std::make_pair(N2, Capacity));
+  // We also insert the reverse edge so that excess preflow can flow backward.
+  N2->Succs.push_back(std::make_pair(N1, 0));
+  DEBUG(dbgs() << "addEdge (" << Capacity << "): " << N1 << " -> " << N2
+               << "\n";
+        dbgs() << "\t"; N1->I->dump(); dbgs() << "\t"; N2->I->dump(););
+}
+
+FlowGraphNode *FencesPRE::getNode(FlowGraph &FlowGraph, Instruction &I) const {
+  // Does nothing if already present.
+  // FIXME: this does one allocation every time.
+  FlowGraph.insert(
+      make_pair(&I, std::unique_ptr<FlowGraphNode>(new FlowGraphNode(&I))));
+  auto Node = FlowGraph[&I].get();
+  return Node;
+}
+
+// FIXME: The first argument is currently unused, will be useful once metadata
+// is attached to fences by AtomicExpand.
+FlowGraphNode *FencesPRE::makeGraphUpwards(const Instruction &FI,
+                                           Instruction &Root,
+                                           FlowGraph &NodeBeforeInsts,
+					   FlowGraph &NodeAfterInsts,
+                                           NodeSubset &Sources) const {
+  auto BB = Root.getParent();
+  DEBUG(dbgs() << "makeGraphUpwards from " << &Root << " : "; Root.dump());
+
+  // Get a reverse iterator at the Root instruction
+  BasicBlock::reverse_iterator it = BB->rbegin();
+  for (; &*it != &Root; ++it) {
+  }
+
+  for (auto b = BB->rend(); it != b; ++it) {
+    if (isWantedFence(*it))
+      continue;
+    switch(chooseOperationUpwards(*it)) {
+      case FencesPREOperation::Stop: {
+        auto Node = getNode(NodeAfterInsts, *it);
+        Sources.insert(Node);
+        return Node;}
+      case FencesPREOperation::Drop:
+        return nullptr;
+      case FencesPREOperation::Continue:
+	switch(chooseOperationDownwards(*it)) {
+	  case FencesPREOperation::Stop: {
+	    if (NodeBeforeInsts.count(&*it)) {
+              return NodeBeforeInsts[&*it].get();
+            } else {
+              auto NodeBeforeIt = getNode(NodeBeforeInsts, *it);
+              auto NodeUp = makeGraphUpwards(FI, *it, NodeBeforeInsts, NodeAfterInsts, Sources);
+              addEdge(NodeUp, NodeBeforeIt);
+              return NodeBeforeIt;
+	    }
+	  }
+          default:
+            continue;
+	}
+    }
+  }
+
+  // We have reached the beginning of the basic block without finding any
+  // reason to stop. Let's continue in the predecessors.
+  auto InsertPt = BB->getFirstInsertionPt();
+  auto Node = getNode(NodeBeforeInsts, *InsertPt);
+  // But first, we should check whether we are at the beginning of the function.
+  if (&BB->getParent()->getEntryBlock() == BB) {
+    Sources.insert(Node);
+    return Node;
+  }
+  for (auto PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
+    // FIXME: add a conservative option where we do not go forward if there is
+    // any of our predecessor that we do not post-dominate.
+    BasicBlock *BBP = *PI;
+    Instruction *TermInst = BBP->getTerminator();
+    if (NodeAfterInsts.count(&*TermInst)) {
+      addEdge(NodeAfterInsts[&*TermInst].get(), Node);
+    } else {
+      auto NodeAfterTermInst = getNode(NodeAfterInsts, *TermInst);
+      auto NodeUp = makeGraphUpwards(FI, *TermInst, NodeBeforeInsts, NodeAfterInsts, Sources);
+      addEdge(NodeUp, NodeAfterTermInst);
+      addEdge(NodeAfterTermInst, Node);
+    }
+  }
+  return Node;
+}
+
+// FIXME: reduce duplication with makeGraphUpwards
+FlowGraphNode *FencesPRE::makeGraphDownwards(const Instruction &FI,
+                                             Instruction &Root,
+                                             FlowGraph &NodeBeforeInsts,
+					     FlowGraph &NodeAfterInsts,
+                                             NodeSubset &Sinks) const {
+  auto BB = Root.getParent();
+  DEBUG(dbgs() << "makeGraphDownwards from " << &Root << " : "; Root.dump());
+
+  // Get an iterator at the Root instruction
+  BasicBlock::iterator it = BB->begin();
+  for (; &*it != &Root; ++it) {
+  }
+
+  for (auto b = BB->end(); it != b; ++it) {
+    if (isWantedFence(*it))
+      continue;
+    switch(chooseOperationDownwards(*it)) {
+      case FencesPREOperation::Stop: {
+        auto Node = getNode(NodeBeforeInsts, *it);
+        Sinks.insert(Node);
+        return Node; }
+      case FencesPREOperation::Drop:
+        return nullptr;
+      case FencesPREOperation::Continue:
+	switch(chooseOperationUpwards(*it)) {
+	  case FencesPREOperation::Stop: {
+	    if (NodeAfterInsts.count(&*it)) {
+              return NodeAfterInsts[&*it].get();
+            } else {
+              auto NodeAfterIt = getNode(NodeAfterInsts, *it);
+              auto NodeDown = makeGraphDownwards(FI, *it, NodeBeforeInsts, NodeAfterInsts, Sinks);
+              addEdge(NodeAfterIt, NodeDown);
+              return NodeAfterIt;
+	    }
+	  }
+          default:
+            continue;
+	}
+    }
+  }
+
+  // We have reached the end of the basic block without finding any
+  // reason to stop. Let's continue in the successors.
+  auto TermInst = BB->getTerminator();
+  auto Node = getNode(NodeAfterInsts, *TermInst);
+  for (auto PI = succ_begin(BB), E = succ_end(BB); PI != E; ++PI) {
+    // FIXME: add a conservative option where we do not go forward if there is
+    // any of our predecessor that we do not post-dominate.
+    BasicBlock *BBS = *PI;
+    Instruction *InsertPt = &*BBS->getFirstInsertionPt();
+    if (NodeBeforeInsts.count(&*InsertPt)) {
+      addEdge(Node, NodeBeforeInsts[&*InsertPt].get());
+    } else {
+      auto NodeBeforeInsertPt = getNode(NodeBeforeInsts, *InsertPt);
+      auto NodeDown = makeGraphDownwards(FI, *InsertPt, NodeBeforeInsts, NodeAfterInsts, Sinks);
+      addEdge(NodeBeforeInsertPt, NodeDown);
+      addEdge(Node, NodeBeforeInsertPt);
+    }
+  }
+  return Node;
+}
+
+/* ----- Implementation of a basic push-relabel min-cut algorithm ----- */
+
+Capacity FencesPRE::getResidualCapacity(Flow &Flow, Capacity C,
+                                        FlowGraphNode &U,
+                                        FlowGraphNode &V) const {
+  if (C != std::numeric_limits<llvm::Capacity>::max())
+    return C - Flow[std::make_pair(&U, &V)];
+  else
+    return C; // We can never saturate an edge with infinite weight (for example
+	      // because it is between different BB).
+}
+
+bool FencesPRE::push(Buckets &B, Flow &Flow, const NodeSubset &S,
+                     const NodeSubset &T, Capacity C, FlowGraphNode &U,
+                     FlowGraphNode &V) const {
+  auto amount = std::min(U.Excess, getResidualCapacity(Flow, C, U, V));
+  if (amount <= 0) return false;
+  Flow[std::make_pair(&U, &V)] += amount;
+  Flow[std::make_pair(&V, &U)] -= amount;
+  U.Excess -= amount;
+  V.Excess += amount;
+  DEBUG(dbgs() << "\t push " << amount << " : " << &U << " -> " << &V << "\n");
+  if (S.count(&V) || T.count(&V)) return false;	// TODO XXX: double check this, segfaults with true,
+		// but I don't remember enough about this code to be confident that false is correct.
+  if (B.size() <= V.Height) B.resize(V.Height + 1);
+  // FIXME: it should probably be a set to remove duplicates for efficiency
+  B[V.Height].push_back(&V);
+  return true;
+}
+
+void FencesPRE::relabel(Flow &Flow, FlowGraphNode &U) const {
+  auto minHeight = std::numeric_limits<Height>::max();
+  for (auto &VWithCap : U.Succs) {
+    auto &V = *VWithCap.first;
+    auto C = VWithCap.second;
+    if (getResidualCapacity(Flow, C, U, V) > 0)
+      minHeight = std::min(minHeight, V.Height + 1);
+  }
+  DEBUG(dbgs() << "\trelabel " << &U << " from " << U.Height << " to "
+               << minHeight << "\n");
+  assert(minHeight != std::numeric_limits<Height>::max());
+  U.Height = minHeight;
+}
+
+Height FencesPRE::discharge(Buckets &B, Flow &Flow, const NodeSubset &S,
+                            const NodeSubset &T, FlowGraphNode &U) const {
+  Height MaxHeight = 0;
+  while (U.Excess > 0) {
+    if (U.Next != U.Succs.end()) {
+      auto VWithCap = *U.Next;
+      auto &V = *VWithCap.first;
+      auto C = VWithCap.second;
+      if (U.Height > V.Height && push(B, Flow, S, T, C, U, V))
+        MaxHeight = std::max(MaxHeight, V.Height);
+      else
+        ++U.Next;
+    } else {
+      relabel(Flow, U);
+      U.Next = U.Succs.begin();
+    }
+  }
+  return MaxHeight;
+}
+
+// TODO: check that this actually computes the optimal cut.
+void FencesPRE::markNode(Flow &Flow, Cut &Cut, FlowGraphNode &U) const {
+  if (U.Mark) return;
+  U.Mark = true;
+  DEBUG(dbgs() << "Marking node " << &U << " : "; U.I->dump());
+  for (auto &VWithCap : U.Succs)
+    if (getResidualCapacity(Flow, VWithCap.second, U, *VWithCap.first) > 0)
+      markNode(Flow, Cut, *VWithCap.first);
+    else if (VWithCap.second != 0)
+      Cut.push_back(std::make_pair(&U, VWithCap.first));
+    // If VWithCap.second == 0, this is a back-edge, that was only useful for the
+    // push/relabel algorithm, but does not exist in the CFG.
+}
+
+void FencesPRE::findCut(const FlowGraph &NodeBeforeInsts, const FlowGraph &NodeAfterInsts,
+			const NodeSubset &Sources, const NodeSubset &Sinks, Cut &Cut) const {
+  Buckets Buckets;
+  // The flow is a separate map and not part of the graph, because when pushing
+  // along an edge U->V we must also update Flow[V->U] and not just Flow[U->V].
+  Flow Flow;
+
+  // First we must make all of the Succs vectors into actual maps.
+  // TODO: In what case can we have any duplicate in N->Succs ?!
+  for (auto &InstToNode : NodeBeforeInsts) {
+    auto N = InstToNode.second.get();
+    // std::sort(N->Succs.begin(), N->Succs.end());
+    // auto last = std::unique(N->Succs.begin(), N->Succs.end());
+    // N->Succs.erase(last, N->Succs.end());
+    // And not forget to initialize the N->Next iterators.
+    N->Next = N->Succs.begin();
+  }
+  for (auto &InstToNode : NodeAfterInsts) {
+    auto N = InstToNode.second.get();
+    // std::sort(N->Succs.begin(), N->Succs.end());
+    // auto last = std::unique(N->Succs.begin(), N->Succs.end());
+    // N->Succs.erase(last, N->Succs.end());
+    // And not forget to initialize the N->Next iterators.
+    N->Next = N->Succs.begin();
+  }
+
+  // Initialization of the sources
+  for (auto S : Sources) {
+    S->Excess = std::numeric_limits<Capacity>::max();
+    S->Height = NodeBeforeInsts.size() + NodeAfterInsts.size();
+    for (auto &VWithCap : S->Succs)
+      push(Buckets, Flow, Sources, Sinks, VWithCap.second, *S, *VWithCap.first);
+  }
+
+  // We are in a trivial case with no more work to do.
+  if (Buckets.size() == 0) {
+    for (auto N : Sources) markNode(Flow, Cut, *N);
+    return;
+  }
+
+  // signed int so we can detect when it hits -1
+  int CurrentActiveHeight = 0;
+  while (CurrentActiveHeight >= 0) {
+    if (Buckets[CurrentActiveHeight].empty()) {
+      --CurrentActiveHeight;
+      continue;
+    }
+    FlowGraphNode &N = *Buckets[CurrentActiveHeight].back();
+    Buckets[CurrentActiveHeight].pop_back();
+
+    DEBUG(dbgs() << "Discharging node " << &N << " : "; N.I->dump());
+    Height NewMaxHeight = discharge(Buckets, Flow, Sources, Sinks, N);
+    CurrentActiveHeight = std::max(CurrentActiveHeight, (int)NewMaxHeight);
+  }
+  // We are done, just produce the cut now;
+  for (auto N : Sources) markNode(Flow, Cut, *N);
+
+  // TODO: fix
+  // if (ViewFencesPREFlowGraph)
+  // ViewGraph(FlowGraphViewer(&FlowGraph, &Sources, &Sinks, &Flow), "");
+}
+
+/* ----- Graph pretty-printing -----
+
+// GraphTraits are used to be able to print the flow-graph for debugging.
+namespace {
+struct FGNSuccsIterator
+    : std::iterator<std::forward_iterator_tag, FlowGraphNode> {
+  std::vector<std::pair<FlowGraphNode *, Capacity> >::iterator InternalIterator;
+  std::vector<std::pair<FlowGraphNode *, Capacity> >::iterator InternalEnd;
+  FGNSuccsIterator(
+      std::vector<std::pair<FlowGraphNode *, Capacity> >::iterator It,
+      std::vector<std::pair<FlowGraphNode *, Capacity> >::iterator End)
+      : InternalIterator(It), InternalEnd(End) {
+    // Skip the first element(s) if it has a capacity of 0.
+    if (It != End && It->second == 0) this->operator++();
+  }
+  iterator &operator++() {
+    do {
+      ++InternalIterator;
+      // We skip all the edges of capacity 0, they are added by the algorithm
+      // for pushing the flow back at the end.
+    } while (InternalIterator != InternalEnd && InternalIterator->second == 0);
+    return *this;
+  }
+  iterator operator++(int n) {
+    auto tmp = *this;
+    ++(*this);
+    return tmp;
+  }
+  // FIXME: this should return a FlowGraphNode&, but then it does not compile.
+  FlowGraphNode *operator*() const { return InternalIterator->first; }
+  FlowGraphNode *operator->() const { return InternalIterator->first; }
+  bool operator==(FGNSuccsIterator &other) {
+    return other.InternalIterator == InternalIterator;
+  }
+  bool operator!=(FGNSuccsIterator other) { return !(*this == other); }
+};
+struct FGNodesIterator
+    : std::iterator<std::forward_iterator_tag, FlowGraphNode> {
+  DenseMap<Instruction *, std::unique_ptr<FlowGraphNode> >::const_iterator
+      InternalIterator;
+  bool IsDup;
+  FGNodesIterator(DenseMap<Instruction *,
+                           std::unique_ptr<FlowGraphNode> >::const_iterator It)
+      : InternalIterator(It), IsDup(false) {}
+  FlowGraphNode *operator->() const {
+    auto NodePtr = InternalIterator->second.get();
+    if (IsDup)
+      return NodePtr->DupNode.get();
+    else
+      return NodePtr;
+  }
+  // FIXME: this should return a FlowGraphNode&, but then it does not compile.
+  FlowGraphNode *operator*() const { return (this->operator->()); }
+  iterator &operator++() {
+    if ((*this)->DupNode) {
+      assert(!IsDup);
+      IsDup = true;
+      return *this;
+    }
+    IsDup = false;
+    ++InternalIterator;
+    return *this;
+  }
+  iterator operator++(int n) {
+    auto tmp = *this;
+    ++(*this);
+    return tmp;
+  }
+  bool operator==(FGNodesIterator &other) {
+    return other.InternalIterator == InternalIterator && other.IsDup == IsDup;
+  }
+  bool operator!=(FGNodesIterator other) { return !(*this == other); }
+};
+}
+namespace llvm {
+template <>
+struct GraphTraits<FlowGraphViewer> {
+  typedef FlowGraphNode NodeType;
+  typedef FlowGraphNode* NodeRef;
+
+  typedef FGNSuccsIterator ChildIteratorType;
+  static ChildIteratorType child_begin(NodeType *N) {
+    return FGNSuccsIterator(N->Succs.begin(), N->Succs.end());
+  }
+  static ChildIteratorType child_end(NodeType *N) {
+    return FGNSuccsIterator(N->Succs.end(), N->Succs.end());
+  }
+
+  typedef FGNodesIterator nodes_iterator;
+  static nodes_iterator nodes_begin(const FlowGraphViewer &G) {
+    return FGNodesIterator(G.InstToNodeMap->begin());
+  }
+  static nodes_iterator nodes_end(const FlowGraphViewer &G) {
+    return FGNodesIterator(G.InstToNodeMap->end());
+  }
+
+  static FlowGraphNode *getEntryNode(const FlowGraphViewer &) {
+    llvm_unreachable("getEntryNode undefined for flowgraphs");
+    // They may very well have several source nodes, and even have unconnected
+    // parts.
+  }
+  static unsigned size(FlowGraphViewer *G) {
+    llvm_unreachable("Size not implemented for flowgraphs.");
+    // And not trivial either, as some nodes may be duplicated, see DupNode in
+    // FlowGraphNode definition.
+  }
+};
+// FIXME: Nodes and their DupNode should probably be linked in the graph
+// FIXME: Different style for edges in the cut.
+template <>
+struct DOTGraphTraits<FlowGraphViewer> : public DefaultDOTGraphTraits {
+  DOTGraphTraits(bool simple = false) : DefaultDOTGraphTraits(simple) {}
+  bool isNodeHidden(FlowGraphNode *N) { return N->Succs.empty(); }
+  static bool hasNodeAddressLabel(const void *N, const FlowGraphViewer &G) {
+    return true;
+  }
+  std::string getNodeLabel(FlowGraphNode *N, const FlowGraphViewer &G) {
+    auto I = N->I;
+    std::string Str;
+    raw_string_ostream OS(Str);
+    if (G.InstToNodeMap->find(I)->second.get() != N) OS << "DUP: ";
+    OS << *I;
+    return OS.str();
+  }
+  static std::string getNodeAttributes(const FlowGraphNode *Node,
+                                       const FlowGraphViewer &G) {
+    // FIXME: SmallPtrSet::count() should accept const pointers
+    auto N = const_cast<FlowGraphNode *>(Node);
+    if (G.Sources->count(N)) return "color=green";
+    if (G.Sinks->count(N)) return "color=blue";
+    return "";
+  }
+  template <typename EdgeIter>
+  static std::string getEdgeAttributes(FlowGraphNode *N, EdgeIter EI,
+                                       const FlowGraphViewer &G) {
+    auto F = G.F->lookup(std::make_pair(N, *EI));
+    auto C = EI.InternalIterator->second;
+    // Color inter-block edges
+    if (C == (std::numeric_limits<uint64_t>::max() >> 1))
+      return "color=red,style=dashed";
+    return ("label=\" " + itostr(F) + "/" + itostr(C) + " \"");
+  }
+};
+}
+*/
diff --git a/lib/Transforms/Scalar/Scalar.cpp b/lib/Transforms/Scalar/Scalar.cpp
index 4e6bc63..7fbae04 100644
--- a/lib/Transforms/Scalar/Scalar.cpp
+++ b/lib/Transforms/Scalar/Scalar.cpp
@@ -39,6 +39,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
   initializeCorrelatedValuePropagationPass(Registry);
   initializeDCELegacyPassPass(Registry);
   initializeDeadInstEliminationPass(Registry);
+  initializeFencesPREPass(Registry);
   initializeScalarizerPass(Registry);
   initializeDSELegacyPassPass(Registry);
   initializeGuardWideningLegacyPassPass(Registry);
diff --git a/test/CodeGen/PowerPC/atomics-fences-pre.ll b/test/CodeGen/PowerPC/atomics-fences-pre.ll
new file mode 100644
index 0000000..0872531
--- /dev/null
+++ b/test/CodeGen/PowerPC/atomics-fences-pre.ll
@@ -0,0 +1,57 @@
+; RUN: llc < %s -mtriple=powerpc-apple-darwin -march=ppc32 -verify-machineinstrs -O=3 | FileCheck %s --check-prefix=CHECK --check-prefix=PPC32
+; FIXME: -verify-machineinstrs currently fail on ppc64 (mismatched register/instruction).
+; This is already checked for in Atomics-64.ll
+; RUN: llc < %s -mtriple=powerpc-apple-darwin -march=ppc64 -O=3 | FileCheck %s --check-prefix=CHECK --check-prefix=PPC64
+
+; sync 1 + sync 1 -> sync 1
+define i32 @acquire_release(i32* %mem) {
+; CHECK-LABEL: acquire_release
+; CHECK: lwz
+; CHECK: lwsync
+; CHECK-NOT: sync
+; CHECK: stw
+  %val = load atomic i32, i32* %mem acquire, align 4
+  store atomic i32 42, i32* %mem release, align 4
+  ret i32 %val
+}
+
+; sync 0 + sync 1 -> sync 0
+define i32 @acquire_seq_cst(i32* %mem) {
+; CHECK-LABEL: acquire_seq_cst
+; CHECK: lwz
+; CHECK: sync
+; CHECK-NOT: sync
+; CHECK: stw
+  %val = load atomic i32, i32* %mem acquire, align 4
+  store atomic i32 42, i32* %mem seq_cst, align 4
+  ret i32 %val
+}
+
+; The insertion of a fence after the monotonic store allows the elimination of
+; the fence before the release store.
+define void @basic-pre(i32* %mem, i1 %cond) {
+; CHECK-LABEL: basic-pre
+entry:
+; CHECK-LABEL: BB#0
+; CHECK: lwz
+; CHECK: lwsync
+; CHECK-NOT: sync
+; CHECK: b
+  %val1 = load atomic i32, i32* %mem acquire, align 4
+  br i1 %cond, label %branch, label %exit
+
+branch:
+; CHECK-LABEL: BB#1
+; CHECK-NOT: sync
+; CHECK: stw
+; CHECK: lwsync
+  store atomic i32 21, i32* %mem monotonic, align 4
+  br label %exit
+
+exit:
+; CHECK-LABEL: LBB2
+; CHECK-NOT: sync
+; CHECK: stw
+  store atomic i32 42, i32* %mem release, align 4
+  ret void
+}
