This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/84188] New: assume non-null malloc pointers are distinct
- From: "msebor at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Sat, 03 Feb 2018 00:08:55 +0000
- Subject: [Bug tree-optimization/84188] New: assume non-null malloc pointers are distinct
- Auto-submitted: auto-generated
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84188
Bug ID: 84188
Summary: assume non-null malloc pointers are distinct
Product: gcc
Version: 8.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: msebor at gcc dot gnu.org
Target Milestone: ---
The manual documents the effect of the malloc attribute like so:
This tells the compiler that a function is malloc-like, i.e., that the
pointer P returned by the function cannot alias any other pointer valid when
the function returns, and moreover no pointers to valid objects occur in any
storage addressed by P.
The following test case shows that GCC doesn't take advantage of this property
nearly to the extent it could. (To enable GCC to make full use of this
property implementations of malloc functions would of course have to avoid such
comparisons internally, but presumably they do that already since that's the
documentation makes it clear that such comparisons must be false.)
$ cat t.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout t.c
void* __attribute__ ((malloc, returns_nonnull))
f (unsigned);
void g0 (unsigned n)
{
extern char a[];
void *p = f (n); // p is non-null
if (p == a) // must be false
__builtin_abort (); // can be eliminated but isn't
}
void g1 (unsigned n)
{
char a[1];
void *p = f (n);
if (p == a) // folded into false
__builtin_abort (); // eliminated (good)
}
void g2 (unsigned n, void *p)
{
// here, p must be valid when f() returns regardless what
// it points to otherwise the equality would be undefined
// therefore p cannot equal q
void *q = f (n);
if (p == q) // must be false
__builtin_abort (); // can be eliminated but isn't
}
void g3 (unsigned n)
{
void *p = f (n);
void *q = f (n);
// the relationship between p and q is the same as in g2
if (p == q) // must be false
__builtin_abort (); // can be eliminated but isn't
}
;; Function g0 (g0, funcdef_no=0, decl_uid=1952, cgraph_uid=0, symbol_order=0)
g0 (unsigned int n)
{
void * p;
<bb 2> [local count: 1073741825]:
p_4 = f (n_2(D));
if (p_4 == &a)
goto <bb 3>; [0.00%]
else
goto <bb 4>; [99.96%]
<bb 3> [count: 0]:
__builtin_abort ();
<bb 4> [local count: 1073312327]:
return;
}
;; Function g1 (g1, funcdef_no=1, decl_uid=1958, cgraph_uid=1, symbol_order=1)
g1 (unsigned int n)
{
<bb 2> [local count: 1073741825]:
f (n_2(D)); [tail call]
return;
}
;; Function g2 (g2, funcdef_no=2, decl_uid=1964, cgraph_uid=2, symbol_order=2)
g2 (unsigned int n, void * p)
{
void * q;
<bb 2> [local count: 1073741825]:
q_4 = f (n_2(D));
if (q_4 == p_5(D))
goto <bb 3>; [0.00%]
else
goto <bb 4>; [99.96%]
<bb 3> [count: 0]:
__builtin_abort ();
<bb 4> [local count: 1073312327]:
return;
}
;; Function g3 (g3, funcdef_no=3, decl_uid=1968, cgraph_uid=3, symbol_order=3)
g3 (unsigned int n)
{
void * q;
void * p;
<bb 2> [local count: 1073741825]:
p_4 = f (n_2(D));
q_6 = f (n_2(D));
if (p_4 == q_6)
goto <bb 3>; [0.00%]
else
goto <bb 4>; [99.96%]
<bb 3> [count: 0]:
__builtin_abort ();
<bb 4> [local count: 1073312327]:
return;
}