literal constant vs variable in math library

前端 未结 4 720
终归单人心
终归单人心 2020-12-03 19:34

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

相关标签:
4条回答
  • 2020-12-03 19:59

    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

    0 讨论(0)
  • 2020-12-03 20:02

    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 and vsprintf 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 :-)

    0 讨论(0)
  • 2020-12-03 20:10

    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
    $ 
    
    0 讨论(0)
  • 2020-12-03 20:19

    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.

    0 讨论(0)
提交回复
热议问题