2cca73
The cprop_hardreg pass is built around the assumption that accessing a
2cca73
register in a narrower mode is the same as accessing the lowpart of
2cca73
the register.  This unfortunately is not true for vector registers on
2cca73
IBM Z. This caused a miscompile of LLVM with GCC 8.5. The problem
2cca73
could not be reproduced with upstream GCC unfortunately but we have to
2cca73
assume that it is latent there. The right fix would require
2cca73
substantial changes to the cprop pass and is certainly something we
2cca73
would want for our platform. But since this would not be acceptable
2cca73
for older GCCs I'll go with what Vladimir proposed in the RedHat BZ
2cca73
and introduce a hopefully temporary and undocumented target hook to
2cca73
disable that specific transformation in regcprop.c.
2cca73
2cca73
--- a/gcc/config/s390/s390.c
2cca73
+++ b/gcc/config/s390/s390.c
2cca73
@@ -10488,6 +10488,18 @@ s390_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
2cca73
   return false;
2cca73
 }
2cca73
 
2cca73
+/* Implement TARGET_NARROW_MODE_REFERS_LOW_PART_P.  */
2cca73
+
2cca73
+static bool
2cca73
+s390_narrow_mode_refers_low_part_p (unsigned int regno)
2cca73
+{
2cca73
+  if (reg_classes_intersect_p (VEC_REGS, REGNO_REG_CLASS (regno)))
2cca73
+    return false;
2cca73
+
2cca73
+  return true;
2cca73
+}
2cca73
+
2cca73
+
2cca73
 /* Implement TARGET_MODES_TIEABLE_P.  */
2cca73
 
2cca73
 static bool
2cca73
@@ -16956,6 +16968,9 @@ s390_case_values_threshold (void)
2cca73
 #undef TARGET_CASE_VALUES_THRESHOLD
2cca73
 #define TARGET_CASE_VALUES_THRESHOLD s390_case_values_threshold
2cca73
 
2cca73
+#undef TARGET_NARROW_MODE_REFERS_LOW_PART_P
2cca73
+#define TARGET_NARROW_MODE_REFERS_LOW_PART_P s390_narrow_mode_refers_low_part_p
2cca73
+
2cca73
 struct gcc_target targetm = TARGET_INITIALIZER;
2cca73
 
2cca73
 #include "gt-s390.h"
2cca73
--- a/gcc/regcprop.c
2cca73
+++ b/gcc/regcprop.c
2cca73
@@ -426,7 +426,8 @@ maybe_mode_change (machine_mode orig_mode, machine_mode copy_mode,
2cca73
 
2cca73
   if (orig_mode == new_mode)
2cca73
     return gen_raw_REG (new_mode, regno);
2cca73
-  else if (mode_change_ok (orig_mode, new_mode, regno))
2cca73
+  else if (mode_change_ok (orig_mode, new_mode, regno)
2cca73
+	   && targetm.narrow_mode_refers_low_part_p (copy_regno))
2cca73
     {
2cca73
       int copy_nregs = hard_regno_nregs (copy_regno, copy_mode);
2cca73
       int use_nregs = hard_regno_nregs (copy_regno, new_mode);
2cca73
--- a/gcc/target.def
2cca73
+++ b/gcc/target.def
2cca73
@@ -5446,6 +5446,16 @@ value that the middle-end intended.",
2cca73
  bool, (machine_mode from, machine_mode to, reg_class_t rclass),
2cca73
  hook_bool_mode_mode_reg_class_t_true)
2cca73
 
2cca73
+/* This hook is used to work around a problem in regcprop. Hardcoded
2cca73
+assumptions currently prevent it from working correctly for targets
2cca73
+where the low part of a multi-word register doesn't align to accessing
2cca73
+the register with a narrower mode.  */
2cca73
+DEFHOOK_UNDOC
2cca73
+(narrow_mode_refers_low_part_p,
2cca73
+"",
2cca73
+bool, (unsigned int regno),
2cca73
+hook_bool_uint_true)
2cca73
+
2cca73
 /* Change pseudo allocno class calculated by IRA.  */
2cca73
 DEFHOOK
2cca73
 (ira_change_pseudo_allocno_class,
2cca73
--- a/gcc/hooks.h
2cca73
+++ b/gcc/hooks.h
2cca73
@@ -86,6 +86,7 @@ extern void hook_void_tree (tree);
2cca73
 extern void hook_void_tree_treeptr (tree, tree *);
2cca73
 extern void hook_void_int_int (int, int);
2cca73
 extern void hook_void_gcc_optionsp (struct gcc_options *);
2cca73
+extern bool hook_bool_uint_true (unsigned int);
2cca73
 extern bool hook_bool_uint_uintp_false (unsigned int, unsigned int *);
2cca73
 
2cca73
 extern int hook_int_uint_mode_1 (unsigned int, machine_mode);
2cca73
--- a/gcc/hooks.c
2cca73
+++ b/gcc/hooks.c
2cca73
@@ -498,6 +498,14 @@ hook_void_gcc_optionsp (struct gcc_optio
2cca73
 {
2cca73
 }
2cca73
 
2cca73
+/* Generic hook that takes an unsigned int and returns true.  */
2cca73
+
2cca73
+bool
2cca73
+hook_bool_uint_true (unsigned int)
2cca73
+{
2cca73
+  return true;
2cca73
+}
2cca73
+
2cca73
 /* Generic hook that takes an unsigned int, an unsigned int pointer and
2cca73
    returns false.  */
2cca73