Err, "GCC does this optimization, because strlen is a "built-in function:"<p>No.
I wrote the optimization pass that does this (GVN PRE with SCC based value numbering).<p>It does it to any pure/const function. Const ones no matter what, and pure ones if it can prove the global memory state does not otherwise change between calls in a way that impacts that pure call (IE there are times it can prove the calls that happen in between don't matter, and will still do the elimination).
You don't usually have to mark the functions const/pure if they are visible to GCC, it does interprocedural analysis to prove they are pure/const and mark them for you.<p>It will even do it through function pointers if the value numbering or alias analysis can prove what they point to, or that they don't change in between the calls.<p><pre><code> double cos (double) __attribute__ ((const));
double sin (double) __attribute__ ((const));
double f(double a)
{
double b;
double c,d;
double (*fp) (double) __attribute__ ((const));
/* Partially redundant call */
if (a < 2.0)
{
fp = sin;
c = fp (a);
}
else
{
c = 1.0;
fp = cos;
}
d = fp (a);
return d + c;
}
</code></pre>
In this example, it will eliminate the unconditional fp(a) call at the end by reusing the value of c in the first if block, and storing the result of calling cos(a) in the else block.
IE:<p><pre><code> double cos (double) __attribute__ ((const));
double sin (double) __attribute__ ((const));
double f(double a)
{
double b;
double c,d;
double (*fp) (double) __attribute__ ((const));
/* Partially redundant call */
if (a < 2.0)
{
fp = sin;
c = fp (a);
temp = c
}
else
{
c = 1.0;
fp = cos;
temp = cos(a)
}
d = temp;
return d + c;
}
</code></pre>
(attribute pure is ignored on function pointers, so you can't just s/const/pure/ and expect it to work)<p>Loop code hoisting is actually a special case of this partial redundancy elimination.<p><pre><code> double sin (double) __attribute__ ((const));
double f (double a)
{
int i;
double c, d;
double (*fp) (double) __attribute__ ((const));
fp = sin;
for (i = 0; i < 50; i++)
{
c = fp (a);
}
d = fp (a);
return d + c;
}
</code></pre>
The call to fp(a) in the loop will be hoisted above the loop through redundancy elimination, the call d = fp(a) will be eliminated in favor of that hoisted value.<p>Basically, the optimization is a <i>lot</i> more powerful than he describes.