This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Question about mem_set_list in propagate_block_info


I'm hoping that someone can help me to better understand how the
following member of the propagate_block_info struct in flow.c is used:

  /* Contains a list of all the MEMs we are tracking for dead store
     elimination.  */
  rtx mem_set_list;

I have an instruction that is being deleted because the compiler
thinks that the location that it is storing to the on stack is dead,
yet that memory is accessed in the very next instruction, though in a
different mode.  In the below fragment from the *.19.cse2 debug file,
the first instruction (insn 11) is gone in the *.20.life file:

  (insn 11 10 13 0 0x4029aa40 (set (mem/f:V16SI (reg/f:SI 1 at) [3 S64 A512])
          (reg:V16SI 210)) 355 {*movv16si_internal} (nil)
      (nil))

  (insn 13 11 21 0 0x4029aa40 (set (reg/v:SI 211 [ m00 ])
          (mem:SI (reg/f:SI 1 at) [4 S4 A32])) 188 {movsi_internal} (nil)
      (nil))

>From my investigation so far, the update_life_info() routine calls
init_propagate_block_info(), and this section of code records the fact
that the stack is written in instruction 11:

  /* If this block has no successors, any stores to the frame that aren't
     used later in the block are dead.  So make a pass over the block
     recording any such that are made and show them dead at the end.  We do
     a very conservative and simple job here.  */
  if (optimize
      && ! (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
            && (TYPE_RETURNS_STACK_DEPRESSED
                (TREE_TYPE (current_function_decl))))
      && (flags & PROP_SCAN_DEAD_STORES)
      && (bb->succ == NULL
          || (bb->succ->succ_next == NULL
              && bb->succ->dest == EXIT_BLOCK_PTR
              && ! current_function_calls_eh_return)))
    {
      rtx insn, set;
      for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
        if (GET_CODE (insn) == INSN
            && (set = single_set (insn))
            && GET_CODE (SET_DEST (set)) == MEM)
          {
            rtx mem = SET_DEST (set);
            rtx canon_mem = canon_rtx (mem);

            /* This optimization is performed by faking a store to the
               memory at the end of the block.  This doesn't work for
               unchanging memories because multiple stores to unchanging
               memory is illegal and alias analysis doesn't consider it.  */
            if (RTX_UNCHANGING_P (canon_mem))
              continue;

            if (XEXP (canon_mem, 0) == frame_pointer_rtx
                || (GET_CODE (XEXP (canon_mem, 0)) == PLUS
                    && XEXP (XEXP (canon_mem, 0), 0) == frame_pointer_rtx
                    && GET_CODE (XEXP (XEXP (canon_mem, 0), 1)) == CONST_INT))
              add_to_mem_set_list (pbi, canon_mem);
          }
    }

I believe that the above simply adds members to the mem_set_list, for
later consideration as dead stores.  For my case, when stopped at a
breakpoint on the call to add_to_mem_set_list, I get:

  2021                  add_to_mem_set_list (pbi, canon_mem);
  (gdb) p debug_rtx(canon_mem)
  (mem/f:V16SI (reg/f:SI 1 at) [3 S64 A512])

which is the destination on the stack that the deleted instruction
stores to.

Then later, insn_dead_p() is called, and the following code gets
executed:

          /* Walk the set of memory locations we are currently tracking
             and see if one is an identical match to this memory location.
             If so, this memory write is dead (remember, we're walking
             backwards from the end of the block to the start).  Since
             rtx_equal_p does not check the alias set or flags, we also
             must have the potential for them to conflict (anti_dependence).  */
          for (temp = pbi->mem_set_list; temp != 0; temp = XEXP (temp, 1))
            if (anti_dependence (r, XEXP (temp, 0)))
              {
                rtx mem = XEXP (temp, 0);

                if (rtx_equal_p (XEXP (canon_r, 0), XEXP (mem, 0))
                    && (GET_MODE_SIZE (GET_MODE (canon_r))
                        <= GET_MODE_SIZE (GET_MODE (mem))))
                  return 1;

For my case, when propagate_block calls propagate_one_insn which calls
insn_dead_p with the value of x below, the rtx from mem_set_list
matches and it returns 1:

  (gdb) p debug_rtx(x)
  (set (mem/f:V16SI (reg/f:SI 1 at) [3 S64 A512])
      (reg:V16SI 210))
  $2 = void
  (gdb) p debug_rtx(temp)
  (expr_list (mem/f:V16SI (reg/f:SI 1 at) [3 S64 A512])
      (nil))
  $3 = void

Since we are walking backwards through the instruction list, I suspect
that what is supposed to happen somewhere is that the compiler is
supposed to notice that instruction 13 (the instruction after the
deleted one) reads at least part of the the memory referenced by the
value in mem_set_list, and remove that entry from the list.

Q: Is the above assumption true?

I could only find a couple of places in flow.c where entries were
removed from the mem_set_list, including mark_used_regs() and
invalidate_mems_from_set().

Thanks for any clarifications on what is supposed to happen here
and figuring out why this instruction is being deleted.

-Fred


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]