So, I know that in C
you need to link the code to the math library, libm
, to be able to use its functions. Today, while I was trying to demonstrate
I think it GCC uses its builtin. I compiled your code with: -fno-builtin-sqrt
and got the expected linker error.
The ISO C90 functions ...
sin
,sprintf
,sqrt
... are all recognized as built-in functions unless-fno-builtin
is specified
That's because gcc
is clever enough to figure out that the square root of the constant 2 is also a constant, so it just generates code like:
mov register, whatever-the-square-root-of-2-is
Hence no need to do a square root calculation at run time, gcc
has already done it at compile time.
This is akin to a benchmarking program which does bucketloads of calculations then does nothing with the result:
int main (void) {
// do something rather strenuous
return 0;
}
You're likely (at high optimisation levels) to see all the do something rather strenuous
code optimised out of existence.
The gcc
docs have a whole page dedicated to these built-ins here and the relevant section in that page for sqrt
and others is:
The ISO C90 functions
abort, abs, acos, asin, atan2, atan, calloc, ceil, cosh, cos, exit, exp, fabs, floor, fmod, fprintf, fputs, frexp, fscanf, isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit, tolower, toupper, labs, ldexp, log10, log, malloc, memchr, memcmp, memcpy, memset, modf, pow, printf, putchar, puts, scanf, sinh, sin, snprintf, sprintf, sqrt, sscanf, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, strstr, tanh, tan, vfprintf, vprintf
andvsprintf
are all recognized as built-in functions unless-fno-builtin
is specified (or-fno-builtin-function
is specified for an individual function).
So, quite a lot, really :-)
As everyone mentions, yes it has to do with constant folding.
With optimizations off, GCC only seems to do it when sqrt(2.0)
is used. Here's the evidence:
Case 1: With the variable.
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
fldl .LC0
fstpl 24(%esp)
fldl 24(%esp)
fsqrt
fucom %st(0)
fnstsw %ax
sahf
jp .L5
je .L2
fstp %st(0)
jmp .L4
.L5:
fstp %st(0)
.L4:
fldl 24(%esp)
fstpl (%esp)
call sqrt
.L2:
fstpl 16(%esp)
movl $.LC1, %eax
fldl 16(%esp)
fstpl 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.align 8
.LC0:
.long 0
.long 1073741824
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
You can see that it emits a call to the sqrt
function. So you'll get a linker error if you don't link the math library.
Case 2: With the Literal.
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
fldl .LC0
fstpl 24(%esp)
movl $.LC1, %eax
fldl 24(%esp)
fstpl 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.align 8
.LC0:
.long 1719614413
.long 1073127582
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
There's no call to sqrt
. Hence no linker error.
With optimizations on, GCC will do constant propagation in both cases. So no linker error in either case.
$ gcc main.c -save-temps
main.o: In function `main':
main.c:(.text+0x30): undefined reference to `sqrt'
collect2: ld returned 1 exit status
$ gcc main.c -save-temps -O2
$
GCC can do constant folding for several standard-library functions. Obviously, if the function is folded at compile-time, there is no need for a run-time function call, so no need to link to libm. You could confirm this by taking a looking at the assembler that the compiler produces (using objdump
or similar).
I guess these optimizations are only triggered when the argument is a constant expression.