Bug 21513

Summary: [4.0/4.1/4.2 Regression] __builtin_expect getting in the way of uninitialized warnings
Product: gcc Reporter: Alexander J. Herrmann <alexander_herrmann>
Component: tree-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: minor CC: bonzini, ed, gcc-bugs, mbligh, pinskia
Priority: P5 Keywords: diagnostic
Version: 4.0.0   
Target Milestone: 4.2.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2005-07-12 06:20:11
Bug Depends on: 22366    
Bug Blocks: 24639    

Description Alexander J. Herrmann 2005-05-11 13:52:36 UTC
Because of my used compiler flags -Werreor it is stated as error insteed of a
warning. The problem is that the compiler complains while there isn't anythin
wrong at all. Worked with 3.4.3. aie_memory_heap_ptr is the variable which the
compiler wrong assumes that it may not be initialized while it is either
initialized or not used within the scope. It may not be a feature :)

Configured with: ../gcc-3.4.3/configure --enable-languages=c,c++,java
--enable-shared --enable-threads=posix --with-cpu=i686 --with-system-zlib
Thread model: posix

Error:
src/aie_memutil.c: In Funktion _aie_malloc:
src/aie_memutil.c:154: Warnung: aie_memory_heap_ptr k&#3670;nnte in dieser Funktion
uninitialisiert verwendet werden
make[1]: *** [obj/aie_memutil.o] Fehler 1
make[1]: Leaving directory `/aIEngine/src/aiengine'
make: *** [install] Fehler 1

aie_memory_heap could be unitilized in this function. It can but if not it's not
used. Difference to GCC 3.4.3.
The function is my own memory allocation setting a overwrite protection for the
allocated memory (post and pre headers) - it is as follows:

void *_aie_malloc(unsigned int size, const char *file, unsigned int line)
{
   void *rc_ptr = NULL;
   struct aie_memory_heap *aie_memory_heap_ptr;
   if (__builtin_expect(((size != 0) &&
       (aie_memory_heap_ptr = (struct aie_memory_heap *)
	                malloc(sizeof(struct aie_memory_heap))) != NULL),true))
   {
      register unsigned int real_size = 
	              size + sizeof(aie_memory_start) + sizeof(aie_memory_end);
      //aie_memory_heap_ptr->file = strdup(file);
      if ((aie_memory_heap_ptr->file = 
	                             (char *)malloc(strlen(file) + 1)) != NULL)
      {
         strcpy(aie_memory_heap_ptr->file, file);
      }
      aie_memory_heap_ptr->line = line;
      aie_memory_heap_ptr->size = size;
      aie_memory_heap_ptr->prev = NULL;
      if (__builtin_expect(
	       ((aie_memory_heap_ptr->next = aie_memory_heap_base) 
		                                          != NULL),true))
      {
         aie_memory_heap_base->prev = aie_memory_heap_ptr;
      }
      if (__builtin_expect(
	       ((aie_memory_heap_ptr->ptr = 
		 (void *)malloc(real_size)) == NULL),false))
      {
         sys_log("%s(%d): Out of Memory?! @ %s(%d)", __FILE__, __LINE__, 
	                                                           file, line);
      }
      else
      {
         memcpy(aie_memory_heap_ptr->ptr, aie_memory_start, 
	                                             sizeof(aie_memory_start));
         memcpy((char *)aie_memory_heap_ptr->ptr +
               (real_size - sizeof(aie_memory_end)), aie_memory_end, 
	                                             sizeof(aie_memory_end));
         *(char *)(rc_ptr = (char *)aie_memory_heap_ptr->ptr + 
	                                      sizeof(aie_memory_start)) = '\0';
      }
      aie_memory_heap_base = aie_memory_heap_ptr;
      if ((aie_akt_mem_usage += size) > aie_max_mem_usage)
      {
         aie_max_mem_usage = aie_akt_mem_usage;
      }
   }
   else
   {
      sys_log("%s(%d): No Memory - Size[%d]?!", __FILE__, __LINE__, size);
   }
   return(rc_ptr);
}

Solution: Waste a byte and maybe a CPU cycle and initilize aie_memory_heap_ptr
it when defined.
Comment 1 Andrew Pinski 2005-05-11 14:06:29 UTC
Confirmed, reduced testcase:
void f(void*);
void *g(void);

void _aie_malloc(unsigned int size)
{
   void *aie_memory_heap_ptr;
   if (__builtin_expect(((size != 0) &&
       (aie_memory_heap_ptr = g()) != 0), 1))
   {
     f(aie_memory_heap_ptr);
   }
}
Comment 2 Andrew Pinski 2005-10-13 01:48:04 UTC
Just a note, I don't think this can be done without removing loop.c
Comment 3 Mark Mitchell 2005-10-31 03:31:36 UTC
This will never be release critical.
Comment 4 Alexander J. Herrmann 2005-11-01 10:46:34 UTC
Subject: Re:  [4.0/4.1 Regression] __builtin_expect getting in the way of uninitialized warnings

Never is a long time. It may become release relevant
as soon as somebody extends the 
-Wunused-value the way other today compiler handle it
like warning me about a value wich is assigned to a
local variable without beeing used.
Sp please consider the workaround code fragment:

int problem_funktion(int a)
{
   int b = 0; // WORKAROUND
   if (__builtin_expect(((a > 0) && ((b = 5) != 0)),
1))
   {
      return(a*b);
   }
   return(a);
} 

Compiled with gcc -Wall -O it produces the no wrong
Warning. As a Value is assigned to b.
I did this quite often as a workaround
http://www.aiengine.org/doc/index.html . But if
somebody whithin the time of never does spend the time
to extend the -Wunused-value the way it works in other
up2date compilers gcc will complain based on the
data-flow analyses that b is assigned the value of 0
which is never used. Imo this can become reality
before never comes which would prevent these code in
any case to be compiled. Doesn't have to P2 but
something higher than P5 would be appriciated so that
somebody may take the time to look into it bevor never
is here. 


Send instant messages to your online friends http://uk.messenger.yahoo.com 
Comment 5 Paolo Bonzini 2005-12-17 10:27:35 UTC
Well, another work around should probably be (untested)

Confirmed, reduced testcase:
void f(void*);
void *g(void);

void _aie_malloc(unsigned int size)
{
   void *aie_memory_heap_ptr;
   if (__builtin_expect(size != 0, true)
     {
       aie_memory_heap_ptr = g();
       if (__builtin_expect (aie_memory_heap_ptr != 0, 1))
         f(aie_memory_heap_ptr);
     }
}

This could be fixed also by folding __builtin_expect of &&, ||, and = like this:

  __b_e (a && b, 1) => __b_e (a, 1) && __b_e (b, 1)
  __b_e (a && b, 0) => a && __b_e (b, 0)
  __b_e (a || b, 1) => a || __b_e (b, 1)
  __b_e (a || b, 0) => __b_e (a, 0) || __b_e (b, 0)
  __b_e (x, y) => (save_expr (x), __b_e (save_expr (x), y)) (*)

(*) when x has side effects

This could even produce better code (I remember a bug about worse code produced when putting complex expression within __builtin_expect, but it might be resolved as of now).
Comment 6 Steven Bosscher 2006-02-27 13:58:43 UTC
Should be fixed by removing the old RTL loop optimizer.
Comment 7 Andrew Pinski 2006-10-23 21:30:15 UTC
*** Bug 29574 has been marked as a duplicate of this bug. ***
Comment 8 Adam Nemet 2007-09-05 19:54:39 UTC
Subject: Bug 21513

Author: nemet
Date: Wed Sep  5 19:54:29 2007
New Revision: 128147

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128147
Log:
	PR tree-optimization/21513
	* builtins.c (build_builtin_expect_predicate): New function.
	(fold_builtin_expect): Add argument for expected value.
	Distribute __builtin_expect over short-circuiting operations.
	Fold nested builtin_expects.
	(fold_builtin_2): Adjust call to fold_builtin_expect.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/builtins.c