diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 26201f375d0afaf47256763701ee9fc3eb16d2fe..1381de22f023934c701210560271c5907a88fecb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2003-02-15  Richard Henderson  <rth@redhat.com>
+
+	* Makefile.in (cfglayout.o): Depend on TARGET_H.
+	* cfglayout.c: Include target.h.
+	(cfg_layout_can_duplicate_bb_p): Check targetm.cannot_copy_insn_p.
+	* target-def.h (TARGET_CANNOT_COPY_INSN_P): New.
+	* target.h (struct gcc_target): Add cannot_copy_insn_p.
+
+	* config/alpha/alpha.c (alpha_cannot_copy_insn_p): New.
+	(TARGET_CANNOT_COPY_INSN_P): New.
+	(override_options): Revert 2003-02-08 hack.
+
 2003-02-15  Richard Henderson  <rth@redhat.com>
 
 	* gcse.c (bypass_block): Use BLOCK_FOR_INSN for resolving LABEL_REFs.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8af0a704c59f5248ea1c6df72afbafd6f68b5514..edab43ecf7ed3b92cfb1ac3894d34641036044b0 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1700,9 +1700,9 @@ bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
 tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
    $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h flags.h \
    $(PARAMS_H) profile.h
-cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
-   insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h function.h \
-   cfglayout.h cfgloop.h
+cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(RTL_H) $(TREE_H) insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h \
+   function.h cfglayout.h cfgloop.h $(TARGET_H)
 timevar.o : timevar.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TIMEVAR_H) flags.h \
    intl.h toplev.h
 regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c
index 7ac9cb6a9d8a86757708d1203c2ae55637b2e7f1..04ba2ec21e038ca0ebe5460d6cc72e7016545a9a 100644
--- a/gcc/cfglayout.c
+++ b/gcc/cfglayout.c
@@ -32,6 +32,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "obstack.h"
 #include "cfglayout.h"
 #include "cfgloop.h"
+#include "target.h"
 
 /* The contents of the current function definition are allocated
    in this obstack, and all are freed at the end of the function.  */
@@ -748,6 +749,21 @@ cfg_layout_can_duplicate_bb_p (bb)
       && (GET_CODE (PATTERN (next)) == ADDR_VEC
 	  || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
     return false;
+
+  /* Do not duplicate blocks containing insns that can't be copied.  */
+  if (targetm.cannot_copy_insn_p)
+    {
+      rtx insn = bb->head;
+      while (1)
+	{
+	  if (INSN_P (insn) && (*targetm.cannot_copy_insn_p) (insn))
+	    return false;
+	  if (insn == bb->end)
+	    break;
+	  insn = NEXT_INSN (insn);
+	}
+    }
+
   return true;
 }
 
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index fcd36338c1036b39c786a73b5885f7966c0cd2d6..c21656df0b4818a20b43b69ddba6b32f57c1491c 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -192,6 +192,8 @@ static int some_small_symbolic_operand_1
   PARAMS ((rtx *, void *));
 static int split_small_symbolic_operand_1
   PARAMS ((rtx *, void *));
+static bool alpha_cannot_copy_insn_p
+  PARAMS ((rtx));
 static bool alpha_rtx_costs
   PARAMS ((rtx, int, int, int *));
 static void alpha_set_memflags_1
@@ -361,6 +363,8 @@ static void unicosmk_unique_section PARAMS ((tree, int));
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall
+#undef TARGET_CANNOT_COPY_INSN_P
+#define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p
 
 #if TARGET_ABI_OSF
 #undef TARGET_ASM_OUTPUT_MI_THUNK
@@ -657,10 +661,6 @@ override_options ()
       real_format_for_mode[DFmode - QFmode] = &vax_g_format;
       real_format_for_mode[TFmode - QFmode] = NULL;
     }
-
-  /* ??? Turn off explicit relocs until code duplication by bb-reorder
-     is addressed.  */
-  target_flags &= ~MASK_EXPLICIT_RELOCS;
 }
 
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -2475,6 +2475,49 @@ split_small_symbolic_operand_1 (px, data)
   return 0;
 }
 
+/* Indicate that INSN cannot be duplicated.  This is true for any insn
+   that we've marked with gpdisp relocs, since those have to stay in
+   1-1 correspondence with one another.
+
+   Techinically we could copy them if we could set up a mapping from one
+   sequence number to another, across the set of insns to be duplicated.
+   This seems overly complicated and error-prone since interblock motion
+   from sched-ebb could move one of the pair of insns to a different block.  */
+
+static bool
+alpha_cannot_copy_insn_p (insn)
+     rtx insn;
+{
+  rtx pat;
+
+  if (!reload_completed || !TARGET_EXPLICIT_RELOCS)
+    return false;
+
+  if (GET_CODE (insn) != INSN)
+    return false;
+  if (asm_noperands (insn) >= 0)
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != SET)
+    return false;
+  pat = SET_SRC (pat);
+  if (GET_CODE (pat) == UNSPEC_VOLATILE)
+    {
+      if (XINT (pat, 1) == UNSPECV_LDGP1
+	  || XINT (pat, 1) == UNSPECV_PLDGP2)
+	return true;
+    }
+  else if (GET_CODE (pat) == UNSPEC)
+    {
+      if (XINT (pat, 1) == UNSPEC_LDGP2)
+	return true;
+    }
+
+  return false;
+}
+
+  
 /* Try a machine-dependent way of reloading an illegitimate address
    operand.  If we find one, push the reload and return the new rtx.  */
    
diff --git a/gcc/target-def.h b/gcc/target-def.h
index dfc590009b38e8dbfc61013c4eba5a191c0e52ce..985d651e3b91987f67e65f1a93de99440485173b 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -259,6 +259,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 /* In hook.c.  */
 #define TARGET_CANNOT_MODIFY_JUMPS_P hook_bool_void_false
 #define TARGET_CANNOT_FORCE_CONST_MEM hook_bool_rtx_false
+#define TARGET_CANNOT_COPY_INSN_P NULL
 #define TARGET_DELEGITIMIZE_ADDRESS hook_rtx_rtx_identity
 #define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_false
 #define TARGET_COMP_TYPE_ATTRIBUTES hook_int_tree_tree_1
@@ -294,6 +295,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   TARGET_SECTION_TYPE_FLAGS,			\
   TARGET_CANNOT_MODIFY_JUMPS_P,			\
   TARGET_CANNOT_FORCE_CONST_MEM,		\
+  TARGET_CANNOT_COPY_INSN_P,			\
   TARGET_DELEGITIMIZE_ADDRESS,			\
   TARGET_FUNCTION_OK_FOR_SIBCALL,		\
   TARGET_IN_SMALL_DATA_P,			\
diff --git a/gcc/target.h b/gcc/target.h
index 8c286f70ad1b8fd0e0f5ab793196cfb0983b10fd..f671321c3ad0bd90652fbab2dfebf1d05cc40e07 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -292,6 +292,9 @@ struct gcc_target
   /* True if the constant X cannot be placed in the constant pool.  */
   bool (* cannot_force_const_mem) PARAMS ((rtx));
 
+  /* True if the insn X cannot be duplicated.  */
+  bool (* cannot_copy_insn_p) PARAMS ((rtx));
+
   /* Given an address RTX, undo the effects of LEGITIMIZE_ADDRESS.  */
   rtx (* delegitimize_address) PARAMS ((rtx));