// Go through the reg notes rooted at NOTE, dropping those that we should drop,
// and preserving those that we want to keep by prepending them to (and
// returning) RESULT. EH_REGION is used to make sure we have at most one
-// REG_EH_REGION note in the resulting list.
+// REG_EH_REGION note in the resulting list. FR_EXPR is used to return any
+// REG_FRAME_RELATED_EXPR note we find, as these can need special handling in
+// combine_reg_notes.
static rtx
-filter_notes (rtx note, rtx result, bool *eh_region)
+filter_notes (rtx note, rtx result, bool *eh_region, rtx *fr_expr)
{
for (; note; note = XEXP (note, 1))
{
copy_rtx (XEXP (note, 0)),
result);
break;
+ case REG_FRAME_RELATED_EXPR:
+ gcc_assert (!*fr_expr);
+ *fr_expr = copy_rtx (XEXP (note, 0));
+ break;
default:
// Unexpected REG_NOTE kind.
gcc_unreachable ();
}
// Return the notes that should be attached to a combination of I1 and I2, where
-// *I1 < *I2.
+// *I1 < *I2. LOAD_P is true for loads.
static rtx
-combine_reg_notes (insn_info *i1, insn_info *i2)
+combine_reg_notes (insn_info *i1, insn_info *i2, bool load_p)
{
+ // Temporary storage for REG_FRAME_RELATED_EXPR notes.
+ rtx fr_expr[2] = {};
+
bool found_eh_region = false;
rtx result = NULL_RTX;
- result = filter_notes (REG_NOTES (i2->rtl ()), result, &found_eh_region);
- return filter_notes (REG_NOTES (i1->rtl ()), result, &found_eh_region);
+ result = filter_notes (REG_NOTES (i2->rtl ()), result,
+ &found_eh_region, fr_expr);
+ result = filter_notes (REG_NOTES (i1->rtl ()), result,
+ &found_eh_region, fr_expr + 1);
+
+ if (!load_p)
+ {
+ // Simple frame-related sp-relative saves don't need CFI notes, but when
+ // we combine them into an stp we will need a CFI note as dwarf2cfi can't
+ // interpret the unspec pair representation directly.
+ if (RTX_FRAME_RELATED_P (i1->rtl ()) && !fr_expr[0])
+ fr_expr[0] = copy_rtx (PATTERN (i1->rtl ()));
+ if (RTX_FRAME_RELATED_P (i2->rtl ()) && !fr_expr[1])
+ fr_expr[1] = copy_rtx (PATTERN (i2->rtl ()));
+ }
+
+ rtx fr_pat = NULL_RTX;
+ if (fr_expr[0] && fr_expr[1])
+ {
+ // Combining two frame-related insns, need to construct
+ // a REG_FRAME_RELATED_EXPR note which represents the combined
+ // operation.
+ RTX_FRAME_RELATED_P (fr_expr[1]) = 1;
+ fr_pat = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, fr_expr[0], fr_expr[1]));
+ }
+ else
+ fr_pat = fr_expr[0] ? fr_expr[0] : fr_expr[1];
+
+ if (fr_pat)
+ result = alloc_reg_note (REG_FRAME_RELATED_EXPR,
+ fr_pat, result);
+
+ return result;
}
// Given two memory accesses in PATS, at least one of which is of a
poly_int64 initial_offset,
unsigned access_size)
{
+ // Punt on frame-related insns, it is better to be conservative and
+ // not try to form writeback pairs here, and means we don't have to
+ // worry about the writeback case in forming REG_FRAME_RELATED_EXPR
+ // notes (see combine_reg_notes).
+ if ((insns[0] && RTX_FRAME_RELATED_P (insns[0]->rtl ()))
+ || RTX_FRAME_RELATED_P (insns[1]->rtl ()))
+ return nullptr;
+
insn_info *pair_dst = pair_range.singleton ();
gcc_assert (pair_dst);
return false;
}
- rtx reg_notes = combine_reg_notes (first, second);
+ rtx reg_notes = combine_reg_notes (first, second, load_p);
rtx pair_pat;
if (writeback_effect)
return false;
}
+ // Punt on frame-related insns with writeback. We probably won't see
+ // these in practice, but this is conservative and ensures we don't
+ // have to worry about these later on.
+ if (writeback && (RTX_FRAME_RELATED_P (i1->rtl ())
+ || RTX_FRAME_RELATED_P (i2->rtl ())))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "rejecting pair (%d,%d): frame-related insn with writeback\n",
+ i1->uid (), i2->uid ());
+ return false;
+ }
+
rtx *ignore = &XEXP (pats[1], load_p);
for (auto use : insns[1]->uses ())
if (!use->is_mem ()
emit_move_insn (move_src, gen_int_mode (aarch64_sve_vg, DImode));
}
rtx base_rtx = stack_pointer_rtx;
- poly_int64 cfa_offset = offset;
+ poly_int64 sp_offset = offset;
HOST_WIDE_INT const_offset;
if (mode == VNx2DImode && BYTES_BIG_ENDIAN)
offset -= fp_offset;
}
rtx mem = gen_frame_mem (mode, plus_constant (Pmode, base_rtx, offset));
+ rtx cfi_mem = gen_frame_mem (mode, plus_constant (Pmode,
+ stack_pointer_rtx,
+ sp_offset));
+ rtx cfi_set = gen_rtx_SET (cfi_mem, reg);
+ bool need_cfi_note_p = (base_rtx != stack_pointer_rtx);
- rtx cfa_base = stack_pointer_rtx;
- if (hard_fp_valid_p && frame_pointer_needed)
- {
- cfa_base = hard_frame_pointer_rtx;
- cfa_offset += (bytes_below_sp - frame.bytes_below_hard_fp);
- }
-
- rtx cfa_mem = gen_frame_mem (mode,
- plus_constant (Pmode,
- cfa_base, cfa_offset));
unsigned int regno2;
if (!aarch64_sve_mode_p (mode)
&& reg == move_src
offset += GET_MODE_SIZE (mode);
insn = emit_insn (aarch64_gen_store_pair (mem, reg, reg2));
- /* The first part of a frame-related parallel insn is
- always assumed to be relevant to the frame
- calculations; subsequent parts, are only
- frame-related if explicitly marked. */
+ rtx cfi_mem2
+ = gen_frame_mem (mode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ sp_offset + GET_MODE_SIZE (mode)));
+ rtx cfi_set2 = gen_rtx_SET (cfi_mem2, reg2);
+
+ /* The first part of a frame-related parallel insn is always
+ assumed to be relevant to the frame calculations;
+ subsequent parts, are only frame-related if
+ explicitly marked. */
if (aarch64_emit_cfi_for_reg_p (regno2))
- {
- const auto off = cfa_offset + GET_MODE_SIZE (mode);
- rtx cfa_mem2 = gen_frame_mem (mode,
- plus_constant (Pmode,
- cfa_base,
- off));
- add_reg_note (insn, REG_CFA_OFFSET,
- gen_rtx_SET (cfa_mem2, reg2));
- }
+ RTX_FRAME_RELATED_P (cfi_set2) = 1;
+
+ /* Add a REG_FRAME_RELATED_EXPR note since the unspec
+ representation of stp cannot be understood directly by
+ dwarf2cfi. */
+ rtx par = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, cfi_set, cfi_set2));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, par);
regno = regno2;
++i;
}
- else if (mode == VNx2DImode && BYTES_BIG_ENDIAN)
- insn = emit_insn (gen_aarch64_pred_mov (mode, mem, ptrue, move_src));
- else if (aarch64_sve_mode_p (mode))
- insn = emit_insn (gen_rtx_SET (mem, move_src));
else
- insn = emit_move_insn (mem, move_src);
+ {
+ if (mode == VNx2DImode && BYTES_BIG_ENDIAN)
+ {
+ insn = emit_insn (gen_aarch64_pred_mov (mode, mem,
+ ptrue, move_src));
+ need_cfi_note_p = true;
+ }
+ else if (aarch64_sve_mode_p (mode))
+ insn = emit_insn (gen_rtx_SET (mem, move_src));
+ else
+ insn = emit_move_insn (mem, move_src);
+
+ if (frame_related_p && (need_cfi_note_p || move_src != reg))
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, cfi_set);
+ }
RTX_FRAME_RELATED_P (insn) = frame_related_p;
- if (frame_related_p)
- add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (cfa_mem, reg));
/* Emit a fake instruction to indicate that the VG save slot has
been initialized. */