information's in each Base Blocks.
This function references the compute_available implementation in lcm.cc */
static void
-compute_reaching_defintion (sbitmap *gen, sbitmap *kill, sbitmap *in,
+compute_reaching_definition (sbitmap *gen, sbitmap *kill, sbitmap *in,
sbitmap *out)
{
edge e;
/* data for avl reaching definition. */
sbitmap *m_reg_def_loc;
+ /* Holds register uses per basic block. Restricted to those registers that
+ are used as vsetvl destinations. */
+ sbitmap *m_reg_use_loc;
+
/* data for vsetvl info reaching definition. */
vsetvl_info m_unknown_info;
auto_vec<vsetvl_info *> m_vsetvl_def_exprs;
sbitmap *m_vsetvl_def_in;
sbitmap *m_vsetvl_def_out;
+ /* Reaching data for vsetvl AVL operands. */
+ sbitmap *m_vsetvl_avl_reach_in;
+ sbitmap *m_vsetvl_avl_reach_out;
+
/* data for lcm */
auto_vec<vsetvl_info *> m_exprs;
sbitmap *m_avloc;
public:
pre_vsetvl ()
- : m_vsetvl_def_in (nullptr), m_vsetvl_def_out (nullptr), m_avloc (nullptr),
+ : m_reg_def_loc (nullptr), m_reg_use_loc (nullptr),
+ m_vsetvl_def_in (nullptr), m_vsetvl_def_out (nullptr),
+ m_vsetvl_avl_reach_in (nullptr), m_vsetvl_avl_reach_out (nullptr),
+ m_avloc (nullptr),
m_avin (nullptr), m_avout (nullptr), m_kill (nullptr), m_antloc (nullptr),
m_transp (nullptr), m_insert (nullptr), m_del (nullptr), m_edges (nullptr)
{
if (m_reg_def_loc)
sbitmap_vector_free (m_reg_def_loc);
+ if (m_reg_use_loc)
+ sbitmap_vector_free (m_reg_use_loc);
if (m_vsetvl_def_in)
sbitmap_vector_free (m_vsetvl_def_in);
if (m_vsetvl_def_out)
sbitmap_vector_free (m_vsetvl_def_out);
+ if (m_vsetvl_avl_reach_in)
+ sbitmap_vector_free (m_vsetvl_avl_reach_in);
+ if (m_vsetvl_avl_reach_out)
+ sbitmap_vector_free (m_vsetvl_avl_reach_out);
+
if (m_avloc)
sbitmap_vector_free (m_avloc);
if (m_kill)
sbitmap_vector_free (m_vsetvl_def_in);
if (m_vsetvl_def_out)
sbitmap_vector_free (m_vsetvl_def_out);
+ if (m_vsetvl_avl_reach_in)
+ sbitmap_vector_free (m_vsetvl_avl_reach_in);
+ if (m_vsetvl_avl_reach_out)
+ sbitmap_vector_free (m_vsetvl_avl_reach_out);
sbitmap *def_loc = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
m_vsetvl_def_exprs.length ());
m_vsetvl_def_out = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
m_vsetvl_def_exprs.length ());
+ m_vsetvl_avl_reach_in
+ = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), GP_REG_LAST + 1);
+ m_vsetvl_avl_reach_out
+ = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), GP_REG_LAST + 1);
+
bitmap_vector_clear (def_loc, last_basic_block_for_fn (cfun));
bitmap_vector_clear (m_kill, last_basic_block_for_fn (cfun));
bitmap_vector_clear (m_vsetvl_def_out, last_basic_block_for_fn (cfun));
bitmap_set_bit (m_vsetvl_def_out[entry->index],
get_expr_index (m_vsetvl_def_exprs, m_unknown_info));
- compute_reaching_defintion (def_loc, m_kill, m_vsetvl_def_in,
- m_vsetvl_def_out);
+ compute_reaching_definition (def_loc, m_kill, m_vsetvl_def_in,
+ m_vsetvl_def_out);
if (dump_file && (dump_flags & TDF_DETAILS))
{
sbitmap_vector_free (def_loc);
sbitmap_vector_free (m_kill);
+
+ /* Now compute the reaching definitions for AVL operands.
+ We can reuse def_loc but index it by regnos now. */
+ def_loc = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+ GP_REG_LAST + 1);
+
+ bitmap_vector_clear (def_loc, last_basic_block_for_fn (cfun));
+ bitmap_vector_clear (m_vsetvl_avl_reach_out, last_basic_block_for_fn (cfun));
+
+ for (const bb_info *bb : crtl->ssa->bbs ())
+ {
+ vsetvl_block_info &block_info = get_block_info (bb);
+ if (block_info.empty_p ())
+ continue;
+ vsetvl_info &info = block_info.get_exit_info ();
+ if (info.has_vl ())
+ bitmap_set_bit (def_loc[bb->index ()], REGNO (info.get_vl ()));
+ }
+
+ compute_reaching_definition (def_loc, m_reg_def_loc, m_vsetvl_avl_reach_in,
+ m_vsetvl_avl_reach_out);
}
/* Subroutine of compute_lcm_local_properties which Compute local transparent
if (info->has_nonvlmax_reg_avl ()
&& bitmap_bit_p (m_reg_def_loc[bb_index], REGNO (info->get_avl ())))
bitmap_clear_bit (m_transp[bb_index], i);
- else if (info->has_vl ()
- && bitmap_bit_p (m_reg_def_loc[bb_index],
- REGNO (info->get_vl ())))
- bitmap_clear_bit (m_transp[bb_index], i);
+ else if (info->has_vl ())
+ {
+ /* If the VL reg is redefined, we cannot move a vsetvl past it. */
+ if (bitmap_bit_p (m_reg_def_loc[bb_index],
+ REGNO (info->get_vl ())))
+ bitmap_clear_bit (m_transp[bb_index], i);
+ /* Same if there is a VL reg use that didn't come from a vsetvl. */
+ else if (bitmap_bit_p (m_reg_use_loc[bb_index],
+ REGNO (info->get_vl ()))
+ && !bitmap_bit_p (m_vsetvl_avl_reach_in[bb_index],
+ REGNO (info->get_vl ())))
+ bitmap_clear_bit (m_transp[bb_index], i);
+ }
}
}
bitmap_vector_clear (m_reg_def_loc, last_basic_block_for_fn (cfun));
bitmap_ones (m_reg_def_loc[ENTRY_BLOCK_PTR_FOR_FN (cfun)->index]);
+ m_reg_use_loc
+ = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), GP_REG_LAST + 1);
+ bitmap_vector_clear (m_reg_use_loc, last_basic_block_for_fn (cfun));
+
+ /* No need to track all GPRs, just use those that are VL destinations.
+ Store them in a bitmap for filtering the uses later on. */
+ auto_bitmap vsetvl_dest_regs;
+ for (bb_info *bb : crtl->ssa->bbs ())
+ for (insn_info *insn : bb->real_nondebug_insns ())
+ {
+ vsetvl_info info = vsetvl_info (insn);
+ if (info.valid_p () && info.has_vl ())
+ bitmap_set_bit (vsetvl_dest_regs, REGNO (info.get_vl ()));
+ }
+
for (bb_info *bb : crtl->ssa->bbs ())
{
auto &block_info = get_block_info (bb);
if (curr_info.valid_p () || curr_info.unknown_p ())
infos.safe_push (curr_info);
- /* Collecting GP registers modified by the current bb. */
if (insn->is_real ())
- for (def_info *def : insn->defs ())
- if (def->is_reg () && GP_REG_P (def->regno ()))
- bitmap_set_bit (m_reg_def_loc[bb->index ()], def->regno ());
+ {
+ /* Collect GPRs modified by the current bb. */
+ for (def_info *def : insn->defs ())
+ if (def->is_reg () && GP_REG_P (def->regno ()))
+ bitmap_set_bit (m_reg_def_loc[bb->index ()], def->regno ());
+ /* Collect non-vsetvl uses of GPRs. */
+ if (!curr_info.valid_p ())
+ {
+ for (use_info *use : insn->uses ())
+ if (use->is_reg () && GP_REG_P (use->regno ())
+ && bitmap_bit_p (vsetvl_dest_regs, use->regno ()))
+ bitmap_set_bit (m_reg_use_loc[bb->index ()],
+ use->regno ());
+ }
+ }
}
vsetvl_info prev_info = vsetvl_info ();
if (!bitmap_bit_p (m_transp[eg->src->index], expr_index))
continue;
+ /* Transparency tells us if we can move upwards without looking
+ down. It is still possible to clobber non-vsetvl uses
+ that happen to share the vsetvl destination register of the
+ vsetvl we are about to hoist.
+ As we have computed the vsetvl VL dest -> vsetvl AVL reach
+ before, we can check if our VL register is live-in for each
+ successor and not reached by a vsetvl. If so, we cannot
+ hoist, as that would clobber the use. */
+ if (curr_info.has_vl ())
+ {
+ edge succ;
+ edge_iterator it;
+ bool clobber = false;
+ FOR_EACH_EDGE (succ, it, eg->src->succs)
+ {
+ if (succ->dest == eg->dest)
+ continue;
+ if (bitmap_bit_p (df_get_live_in (succ->dest),
+ REGNO (curr_info.get_vl ()))
+ && !bitmap_bit_p
+ (m_vsetvl_avl_reach_in[succ->dest->index],
+ REGNO (curr_info.get_vl ())))
+ {
+ clobber = true;
+ break;
+ }
+ }
+ if (clobber)
+ continue;
+ }
+
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
- " Set empty bb %u to info:", eg->src->index);
+ " Hoisting vsetvl info from bb %u to "
+ "bb %u: ", eg->dest->index, eg->src->index);
curr_info.dump (dump_file, " ");
}
src_block_info.set_info (curr_info);