Multiple set insns reload problem.

Jan Hubicka
Tue Jan 11 09:57:00 GMT 2000

In multiple set insns the output reloads are tricky, because the destination address
of one output reload may mention register used as output of insn.
So the separate move insn will put the value to bad destination.

Global.c contains code that probably attempts to avoid it:

	      /* If INSN has multiple outputs, then any reg that dies here
		 and is used inside of an output
		 must conflict with the other outputs.

		 It is unsafe to use !single_set here since it will ignore an
		 unused output.  Just because an output is unused does not mean
		 the compiler can assume the side effect will not occur.
		 Consider if REG appears in the address of an output and we
		 reload the output.  If we allocate REG to the same hard
		 register as an unused output we could set the hard register
		 before the output reload insn.  */
	      if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
		for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
		  if (REG_NOTE_KIND (link) == REG_DEAD)
		      int used_in_output = 0;
		      int i;
		      rtx reg = XEXP (link, 0);

		      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
			  rtx set = XVECEXP (PATTERN (insn), 0, i);
			  if (GET_CODE (set) == SET
			      && GET_CODE (SET_DEST (set)) != REG
			      && !rtx_equal_p (reg, SET_DEST (set))
			      && reg_overlap_mentioned_p (reg, SET_DEST (set)))
			    used_in_output = 1;
		      if (used_in_output)
			mark_reg_conflicts (reg);

The problem is that pseudo may not conflict with itself, so when one pseudo is used
for both in the address and as output, the colision bit is meaningless.
Second problem is with the clobbers, that produce REG_UNUSED instad of REG_DEAD note.
This problem is easy to fix anyway...

The bug can be easilly trigered by the following testcase:

int a;
  int *ptr=&a;
  asm("":"=r"(ptr):"0"(&a));  /* Hide the constant address behind cse */
  asm("movl $0,%0 ; movl $0,%1":"=m,r"(*ptr),"=,c"(ptr));

(it clears ptr and writes zero the the address pointed by ptr).
The resulting code is:

	movl $0,%eax ; movl $0,%ecx
	movl	%eax, (%ecx)  <--- incorrect spill insn

And results in incorrect code storing to NULL pointer.

Any ideas how to fix this?


More information about the Gcc-bugs mailing list