为什么将 const 属性应用于纯函数不能减少运行时间?

Why applying a const attribute to a pure function cannot reduce elapsed time?

根据 GNU document:

int square (int) __attribute__ ((const)) tells GCC that subsequent calls to function square with the same argument value can be replaced by the result of the first call regardless of the statements in between.

我预计在函数声明中删除 __attribute__((const)) 后,以下代码会变慢。

#include <stdio.h>
#include <limits.h>

int my_double(int b) __attribute__((const));

//int my_double(int b);


int main(void) {

  long result = 0;

  for (int i = 0; i < INT_MAX/2; i++)
  {
     result += my_double(5);
  }

  printf("%ld\n", result);
}

int my_double(int b) {
  return b*2;
}

然而,实验表明__attribute__((const))不会显着影响计时结果。有谁知道原因吗?谢谢。

顺便说一下,我使用以下命令清除任何可能污染每个实验计时结果的缓存。

  sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
  sudo swapoff -a
  sudo swapon -a

并使用 /usr/bin/time 为实验计时。

PS。对应的程序集如下:(我对程序集不熟悉)

    .file   "attribute-o.c"
    .text
    .section    .rodata
.LC0:
    .string "%ld\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    , %rsp
    movq    [=12=], -8(%rbp)
    movl    [=12=], -12(%rbp)
    jmp .L2
.L3:
    movl    , %edi
    call    my_double
    cltq
    addq    %rax, -8(%rbp)
    addl    , -12(%rbp)
.L2:
    cmpl    73741822, -12(%rbp)
    jle .L3
    movq    -8(%rbp), %rax
    movq    %rax, %rsi
    leaq    .LC0(%rip), %rax
    movq    %rax, %rdi
    movl    [=12=], %eax
    call    printf@PLT
    movl    [=12=], %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .globl  my_double
    .type   my_double, @function
my_double:
.LFB1:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    addl    %eax, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   my_double, .-my_double
    .ident  "GCC: (Ubuntu 11.2.0-7ubuntu2) 11.2.0"
    .section    .note.GNU-stack,"",@progbits
    .section    .note.gnu.property,"a"
    .align 8
    .long   1f - 0f
    .long   4f - 1f
    .long   5
0:
    .string "GNU"
1:
    .align 8
    .long   0xc0000002
    .long   3f - 2f
2:
    .long   0x3
3:
    .align 8
4:

__attribute__ ((const)) 是关于在同一个表达式.

中删除公共子表达式

表达式my_double(5)中没有公共子表达式,所以没有什么可以去掉,生成的代码是一样的。

如果将my_double(5)替换为my_double(5) + my_double(5),则有两个公共子表达式。由于编译器不知道 my_double(5) 做了什么(可能有副作用),所以必须调用 my_double(5) 两次,除非编译器知道 my_double 没有副作用(因为 __attribute__ ((const))) 然后my_double(5)只能调用一次,结果可以相加

在这里查看:https://www.godbolt.org/z/bGnfq9zM5