Index: tree-ssa-loop-im.c
===================================================================
--- tree-ssa-loop-im.c	(revision 170745)
+++ tree-ssa-loop-im.c	(working copy)
@@ -377,6 +377,11 @@ movement_possibility (gimple stmt)
       || stmt_could_throw_p (stmt))
     return MOVE_IMPOSSIBLE;
 
+  /* Do not move loads of globals if under a restrictive memory model.  */
+  if (PARAM_VALUE (PARAM_ALLOW_LOAD_DATA_RACES) == 0
+      && gimple_has_thread_visible_ops (stmt))
+    return MOVE_IMPOSSIBLE;
+
   if (is_gimple_call (stmt))
     {
       /* While pure or const call is guaranteed to have no side effects, we
Index: tree.h
===================================================================
--- tree.h	(revision 170745)
+++ tree.h	(working copy)
@@ -3102,6 +3102,10 @@ struct GTY(()) tree_parm_decl {
 #define DECL_THREAD_LOCAL_P(NODE) \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model >= TLS_MODEL_REAL)
 
+/* Return true if a VAR_DECL is visible from another thread.  */
+#define DECL_THREAD_VISIBLE_P(NODE) \
+  (TREE_STATIC (NODE) && !DECL_THREAD_LOCAL_P (NODE))
+
 /* In a non-local VAR_DECL with static storage duration, true if the
    variable has an initialization priority.  If false, the variable
    will be initialized at the DEFAULT_INIT_PRIORITY.  */
Index: cse.c
===================================================================
--- cse.c	(revision 170745)
+++ cse.c	(working copy)
@@ -2402,6 +2402,19 @@ hash_rtx_cb (const_rtx x, enum machine_m
       }
 
     case MEM:
+      /* Avoid hoisting loads of globals if under a restrictive memory
+	 model.  */
+      if (PARAM_VALUE (PARAM_ALLOW_LOAD_DATA_RACES) == 0)
+	{
+	  tree decl = MEM_EXPR (x);
+	  if (do_not_record_p
+	      && decl && TREE_CODE (decl) == VAR_DECL
+	      && DECL_THREAD_VISIBLE_P (decl))
+	    {
+	      *do_not_record_p = 1;
+	      return 0;
+	    }
+	}
       /* We don't record if marked volatile or if BLKmode since we don't
 	 know the size of the move.  */
       if (do_not_record_p && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
Index: cselib.c
===================================================================
--- cselib.c	(revision 170745)
+++ cselib.c	(working copy)
@@ -1190,6 +1190,16 @@ cselib_lookup_mem (rtx x, int create)
   cselib_val *mem_elt;
   struct elt_list *l;
 
+  /* Forget any reads from globals if under a restrictive memory
+     model.  */
+  if (PARAM_VALUE (PARAM_ALLOW_LOAD_DATA_RACES) == 0)
+    {
+      tree decl = MEM_EXPR (x);
+      if (decl && TREE_CODE (decl) == VAR_DECL
+	  && DECL_THREAD_VISIBLE_P (decl))
+	return 0;
+    }
+
   if (MEM_VOLATILE_P (x) || mode == BLKmode
       || !cselib_record_memory
       || (FLOAT_MODE_P (mode) && flag_float_store))
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c	(revision 170745)
+++ tree-ssa-pre.c	(working copy)
@@ -4000,6 +4000,12 @@ compute_avail (void)
 	      || stmt_could_throw_p (stmt))
 	    continue;
 
+	  /* Do not move loads of globals if under a restrictive
+	     memory model.  */
+	  if (PARAM_VALUE (PARAM_ALLOW_LOAD_DATA_RACES) == 0
+	      && gimple_has_thread_visible_ops (stmt))
+	    continue;
+
 	  switch (gimple_code (stmt))
 	    {
 	    case GIMPLE_RETURN:
Index: gimple.c
===================================================================
--- gimple.c	(revision 170745)
+++ gimple.c	(working copy)
@@ -2388,6 +2388,36 @@ gimple_rhs_has_side_effects (const_gimpl
   return false;
 }
 
+/* Return true if any of the operands in S are visible from another
+   thread (globals that are not TLS.  */
+/* ?? If this becomes a performance penalty, we should cache this
+   value as we do with volatiles.  */
+
+bool
+gimple_has_thread_visible_ops (const_gimple s)
+{
+  unsigned int i;
+
+  if (is_gimple_debug (s))
+    return false;
+
+  if (is_gimple_assign (s))
+    {
+      /* Skip the LHS.  */
+      i = 1;
+    }
+  else
+    i = 0;
+  for (; i < gimple_num_ops (s); i++)
+    {
+      tree op = gimple_op (s, i);
+      if (op && TREE_CODE (op) == VAR_DECL
+	  && DECL_THREAD_VISIBLE_P (op))
+	return true;
+    }
+  return false;
+}
+
 /* Helper for gimple_could_trap_p and gimple_assign_rhs_could_trap_p.
    Return true if S can trap.  When INCLUDE_MEM is true, check whether
    the memory operations could trap.  When INCLUDE_STORES is true and
Index: gimple.h
===================================================================
--- gimple.h	(revision 170745)
+++ gimple.h	(working copy)
@@ -882,6 +882,7 @@ gimple gimple_build_cond_from_tree (tree
 void gimple_cond_set_condition_from_tree (gimple, tree);
 bool gimple_has_side_effects (const_gimple);
 bool gimple_rhs_has_side_effects (const_gimple);
+bool gimple_has_thread_visible_ops (const_gimple);
 bool gimple_could_trap_p (gimple);
 bool gimple_could_trap_p_1 (gimple, bool, bool);
 bool gimple_assign_rhs_could_trap_p (gimple);
