Bug 25399 - bogus 'clobbered by longjmp' message caused by partly uninitialized pesdo register
Summary: bogus 'clobbered by longjmp' message caused by partly uninitialized pesdo reg...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.2.0
: P3 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2005-12-13 22:04 UTC by Dale Johannesen
Modified: 2006-01-28 20:09 UTC (History)
1 user (show)

See Also:
Host:
Target: powerpc-*
Build:
Known to work:
Known to fail: 3.3.3 4.1.0 4.0.0
Last reconfirmed: 2005-12-13 22:33:16


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dale Johannesen 2005-12-13 22:04:00 UTC
(I don't think this is the same as any of the similar bugs, although I could be wrong.)
In this case the field assignments cover all of u, so none of it is actually live across
the call, but dataflow can't figure this out.  

While this bogus warning is the only visible effect I know of, fixing this would also
decrease register pressure and might result in improved code quality in some cases.

 struct ss { unsigned short a; unsigned short b; };
 union uu { unsigned int all; struct ss parts; };
#include <setjmp.h>

extern void bar(union uu);
extern void baz();

void foo() {
  for(;;)
  {
    union uu u;
    jmp_buf env;
    u.parts.a = 0;
    u.parts.b = 0;
    bar(u);
    if (setjmp(env)==0)
      baz();
    else
      baz();
  }
}
Comment 1 Andrew Pinski 2005-12-13 22:33:16 UTC
Actually reading the RTL, it would not help register pressure at all since the set is done right before the call to bar and is not pull out of the loop.  
What is happening is that u is being assigned a pesdu register and not just a stack slot and the reason why it does not know it is set only once and not used after is because at the point we run life analysis, we have the following RTL:
(insn:HI 76 77 55 0 (set (reg/v:SI 120 [ u ])
        (const_int 0 [0x0])) 326 {*movsi_internal1} (nil)
    (nil))

....
// BEGIN LOOP

(insn:HI 14 78 15 2 (set (reg:SI 121)
        (const_int 0 [0x0])) 326 {*movsi_internal1} (nil)
    (nil))

(insn:HI 15 14 18 2 (set (zero_extract:SI (reg/v:SI 120 [ u ])
            (const_int 16 [0x10])
            (const_int 0 [0x0]))
        (reg:SI 121)) 160 {insvsi} (insn_list:REG_DEP_TRUE 14 (nil))
    (nil))

(insn:HI 18 15 20 2 (set (zero_extract:SI (reg/v:SI 120 [ u ])
            (const_int 16 [0x10])
            (const_int 16 [0x10]))
        (reg:SI 121)) 160 {insvsi} (insn_list:REG_DEP_TRUE 15 (nil))
    (expr_list:REG_DEAD (reg:SI 121)
        (nil)))


But we have not simplified that down to just r120 = 0.

Which we do in combine.  Life analysis adds the r120 in the first BB as it was being used uninitialized.

Confirmed, not a regression.
Comment 2 Andrew Pinski 2005-12-13 22:42:12 UTC
One more thing If I do:
 struct ss { unsigned short a; unsigned short b; };
 union uu { unsigned int all; struct ss parts; };
#include <setjmp.h>

extern void bar(union uu);
extern void baz();

void foo() {
  for(;;)
  {
    union uu u;
    jmp_buf env;
    u.parts.a = f();
    u.parts.b = u.parts.a;
    bar(u);
    if (setjmp(env)==0)
      baz1();
    else
      baz();
  }
}
I still get a warning but it actually will not be clobbered as it is spilled anyways.  Maybe we are warning for structs/unions as they are going to be spilled anyways.
Comment 3 Dale Johannesen 2005-12-13 22:54:18 UTC
(In the original example) note the bit vectors at beginning and end of blocks show 120 as live throughout the loop, although it isn't really.  That's why I think it affects register pressure.  GRA does do some munging of those bit vectors though, maybe it fixes this.
Comment 4 Andrew Pinski 2005-12-13 23:03:43 UTC
(In reply to comment #3)
> (In the original example) note the bit vectors at beginning and end of blocks
> show 120 as live throughout the loop, although it isn't really.  That's why I
> think it affects register pressure.  GRA does do some munging of those bit
> vectors though, maybe it fixes this.

And the reason why it is done that way is because it is used uninitialized and with
zero_extract.  Now if we do some live analysis at the tree level and find out that the
union is only set/used in the loop, we should be able to emit the set r120 in the loop
when expanding (but we currently don't).

Hmm, Actually I was wrong in saying that we get li r3, 0 inside the loop.
There is some missed optimizations here.  First the following is not simplified:
.....

(insn 14 12 15 (set (reg:SI 121)
        (const_int 0 [0x0])) -1 (nil)
    (nil))

(insn 15 14 0 (set (zero_extract:SI (reg/v:SI 120 [ u ])
            (const_int 16 [0x10])
            (const_int 0 [0x0]))
        (reg:SI 121)) -1 (nil)
    (nil))

into:

(set (reg:SI 120) (const_int 0))

if 120 is uninitialized.  That will fix the issue fully for both of the issue.  Maybe not as it is only partly uninitailized as 120 is initialized after going through the loop.

Maybe we need better optimizations with uninitialized pesdu registers at the rtl level.
Currently we just put a (set r120 0) in the first BB.
Comment 5 Dale Johannesen 2005-12-13 23:19:23 UTC
This slight modification shows another problem:  when the message refers to an inlined copy of a variable, it points to the inlined function body and variable rather than the place where the problem is.  In the following you get 

small2.c: In function 'foo':
small2.c:9: warning: variable 'temp' might be clobbered by 'longjmp' or 'vfork'

which has proved baffling to people who've hit it: there is no 'temp' in foo, and no 'setjmp' in the function that does contain a temp.  (In the maximally confusing case, foo could contain a completely unrelated 'temp' which is visibly not live across a setjmp.)

  struct ss { unsigned short a; unsigned short b; };
  union uu { unsigned int all; struct ss parts; };
#include <setjmp.h>

extern void bar(union uu);
extern void baz();

union uu func(union uu uuin) {
  union uu temp;
  if (uuin.parts.b)
    return uuin;
  temp.parts.a = 0; temp.parts.b = 0;
  return temp;
}
void foo(int i, union uu uuin) {
  for(;;)
  {
    union uu u = func(uuin);
    jmp_buf env;
    bar(u);
    if (setjmp(env)==0)
      baz();
    else
      baz();
  }
}