The h8sx multilib fails to build because h8300_swap_into_er6
used the push function, which set RTX_FRAME_RELATED_P.  This
resulted in mismatched (and incorrect) unwind info across two
different execution paths.

The trivial solution is to unset RTX_FRAME_RELATED_P from 
the push, but it's now possible to generate Really Correct
unwind info for the sequence around movmd.

Tested insofar as the multilib now builds, and visually
inspecting the readelf dump of the unwind info.  Committed.


r~
        * config/h8300/h8300.c (push, pop): Return the insn.
        (h8300_swap_into_er6): Generate correct unwind info.
        (h8300_swap_out_of_er6): Likewise.


diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index ef48395..a929a28 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -87,8 +87,6 @@ static int h8300_os_task_function_p (tree);
 static void h8300_emit_stack_adjustment (int, HOST_WIDE_INT, bool);
 static HOST_WIDE_INT round_frame_size (HOST_WIDE_INT);
 static unsigned int compute_saved_regs (void);
-static void push (int);
-static void pop (int);
 static const char *cond_string (enum rtx_code);
 static unsigned int h8300_asm_insn_count (const char *);
 static tree h8300_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
@@ -556,7 +554,7 @@ compute_saved_regs (void)
 
 /* Emit an insn to push register RN.  */
 
-static void
+static rtx
 push (int rn)
 {
   rtx reg = gen_rtx_REG (word_mode, rn);
@@ -570,11 +568,12 @@ push (int rn)
     x = gen_push_h8300hs_normal (reg);
   x = F (emit_insn (x), true);
   add_reg_note (x, REG_INC, stack_pointer_rtx);
+  return x;
 }
 
 /* Emit an insn to pop register RN.  */
 
-static void
+static rtx
 pop (int rn)
 {
   rtx reg = gen_rtx_REG (word_mode, rn);
@@ -588,6 +587,7 @@ pop (int rn)
     x = gen_pop_h8300hs_normal (reg);
   x = emit_insn (x);
   add_reg_note (x, REG_INC, stack_pointer_rtx);
+  return x;
 }
 
 /* Emit an instruction to push or pop NREGS consecutive registers
@@ -2678,7 +2678,16 @@ h8sx_emit_movmd (rtx dest, rtx src, rtx length,
 void
 h8300_swap_into_er6 (rtx addr)
 {
-  push (HARD_FRAME_POINTER_REGNUM);
+  rtx insn = push (HARD_FRAME_POINTER_REGNUM);
+  if (frame_pointer_needed)
+    add_reg_note (insn, REG_CFA_DEF_CFA,
+                 plus_constant (gen_rtx_MEM (Pmode, stack_pointer_rtx),
+                                2 * UNITS_PER_WORD));
+  else
+    add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                              plus_constant (stack_pointer_rtx, 4)));
+
   emit_move_insn (hard_frame_pointer_rtx, addr);
   if (REGNO (addr) == SP_REG)
     emit_move_insn (hard_frame_pointer_rtx,
@@ -2692,9 +2701,20 @@ h8300_swap_into_er6 (rtx addr)
 void
 h8300_swap_out_of_er6 (rtx addr)
 {
+  rtx insn;
+
   if (REGNO (addr) != SP_REG)
     emit_move_insn (addr, hard_frame_pointer_rtx);
-  pop (HARD_FRAME_POINTER_REGNUM);
+
+  insn = pop (HARD_FRAME_POINTER_REGNUM);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  if (frame_pointer_needed)
+    add_reg_note (insn, REG_CFA_DEF_CFA,
+                 plus_constant (hard_frame_pointer_rtx, 2 * UNITS_PER_WORD));
+  else
+    add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                              plus_constant (stack_pointer_rtx, -4)));
 }
 
 /* Return the length of mov instruction.  */
diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 99b37ab..69218cb2d 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -778,8 +778,8 @@ def_cfa_1 (dw_cfa_location *new_cfa)
   if (cfi)
     {
       cur_row->cfa = *new_cfa;
-      if (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression)
-        cur_row->cfa_cfi = cfi;
+      cur_row->cfa_cfi = (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression
+                         ? cfi : NULL);
 
       add_cfi (cfi);
     }
@@ -1205,18 +1205,13 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
 
   memset (&loc, 0, sizeof (loc));
 
-  switch (GET_CODE (pat))
+  if (GET_CODE (pat) == PLUS)
     {
-    case PLUS:
-      loc.reg = dwf_regno (XEXP (pat, 0));
       loc.offset = INTVAL (XEXP (pat, 1));
-      break;
-
-    case REG:
-      loc.reg = dwf_regno (pat);
-      break;
-
-    case MEM:
+      pat = XEXP (pat, 0);
+    }
+  if (MEM_P (pat))
+    {
       loc.indirect = 1;
       pat = XEXP (pat, 0);
       if (GET_CODE (pat) == PLUS)
@@ -1224,13 +1219,11 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
          loc.base_offset = INTVAL (XEXP (pat, 1));
          pat = XEXP (pat, 0);
        }
-      loc.reg = dwf_regno (pat);
-      break;
-
-    default:
-      /* Recurse and define an expression.  */
-      gcc_unreachable ();
     }
+  /* ??? If this fails, we could be calling into the _loc functions to
+     define a full expression.  So far no port does that.  */
+  gcc_assert (REG_P (pat));
+  loc.reg = dwf_regno (pat);
 
   def_cfa_1 (&loc);
 }

Reply via email to