www.91084.com

GVKun编程网logo

c – 为什么__builtin_prefetch在这里没有任何影响?(为什么c++中用不了cin)

20

这篇文章主要围绕c–为什么__builtin_prefetch在这里没有任何影响?和为什么c++中用不了cin展开,旨在为您提供一份详细的参考资料。我们将全面介绍c–为什么__builtin_pref

这篇文章主要围绕c – 为什么__builtin_prefetch在这里没有任何影响?为什么c++中用不了cin展开,旨在为您提供一份详细的参考资料。我们将全面介绍c – 为什么__builtin_prefetch在这里没有任何影响?的优缺点,解答为什么c++中用不了cin的相关问题,同时也会为您带来c – __builtin_unreachable有哪些优化方便?、c – 如何实施“__builtin_va_list”?、C++ 中的 __builtin_expect、C++ 的位运算:__builtin, bitset的实用方法。

本文目录一览:

c – 为什么__builtin_prefetch在这里没有任何影响?(为什么c++中用不了cin)

c – 为什么__builtin_prefetch在这里没有任何影响?(为什么c++中用不了cin)

我正在编写一个解析文件的程序.它由一个主循环组成,逐个字符地解析并处理它们.这是主循环:
char c;
char * ptr;

for( size_t i = 0; i < size ; ++i )
{
    ptr = ( static_cast<char*>(sentenceMap) + i );
    c = *ptr;

    __builtin_prefetch( ptr + i + 1 );

   // some treatment on ptr and c   
}

如您所见,我添加了一条builtin_prefetch指令,希望在我的循环的下一次迭代中放入缓存.我尝试了不同的值:ptr i 1,ptr i 2,ptr i 10但似乎没有任何改变.

为了测量性能,我使用valgrind的工具cachegrind,它给出了缓存未命中数的指示.在行c = * ptr上,当未设置__builtin_prefetch时,cachegrind记录632,378 DLmr(L3缓存未命中).但奇怪的是,无论我设置为__builtin_prefetch的参数如何,此值都不会更改.

对此有何解释?

解决方法

那是因为硬件比您早多年.

总结

以上是小编为你收集整理的c – 为什么__builtin_prefetch在这里没有任何影响?全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

c – __builtin_unreachable有哪些优化方便?

c – __builtin_unreachable有哪些优化方便?

从 gcc的文档来看

If control flow reaches the point of the __builtin_unreachable,the program is undefined.

我认为__builtin_unreachable可以用作各种创造性方式的优化器提示.所以我做了一个小实验

void stdswap(int& x,int& y)
{
    std::swap(x,y);
}

void brswap(int& x,int& y)
{
    if(&x == &y)
        __builtin_unreachable();
    x ^= y;
    y ^= x;
    x ^= y;
}

void rswap(int& __restrict x,int& __restrict y)
{
    x ^= y;
    y ^= x;
    x ^= y;
}

gets compiled to(g -O2)

stdswap(int&,int&):
        mov     eax,DWORD PTR [rdi]
        mov     edx,DWORD PTR [rsi]
        mov     DWORD PTR [rdi],edx
        mov     DWORD PTR [rsi],eax
        ret
brswap(int&,DWORD PTR [rdi]
        xor     eax,eax
        xor     eax,DWORD PTR [rsi]
        mov     DWORD PTR [rsi],eax
        xor     DWORD PTR [rdi],eax
        ret
rswap(int&,DWORD PTR [rsi]
        mov     edx,DWORD PTR [rdi]
        mov     DWORD PTR [rdi],eax
        mov     DWORD PTR [rsi],edx
        ret

我假设从优化器的角度来看,stdswap和rswap是最佳的.为什么不将brswap编译成同一个东西?我能用__builtin_unreachable将它编译成同样的东西吗?

解决方法

__builtin_unreachable的目的是帮助编译器删除死代码(程序员知道永远不会被执行)并通过让编译器知道路径是“冷”来线性化代码.考虑以下:

void exit_if_true(bool x);

int foo1(bool x)
{
    if (x) {
        exit_if_true(true);
        //__builtin_unreachable(); // we do not enable it here
    } else {
        std::puts("reachable");
    }

    return 0;
}
int foo2(bool x)
{
    if (x) {
        exit_if_true(true);
        __builtin_unreachable();  // Now compiler kNows exit_if_true
                                  // will not return as we are passing true to it
    } else {
        std::puts("reachable");
    }

    return 0;
}

生成的代码:

foo1(bool):
        sub     rsp,8
        test    dil,dil
        je      .L2      ; that jump is going to change as branches will be swapped
        mov     edi,1
        call    exit_if_true(bool)
        xor     eax,eax ; that tail is going to be removed
        add     rsp,8
        ret
.L2:
        mov     edi,OFFSET FLAT:.LC0
        call    puts
        xor     eax,eax
        add     rsp,8
        ret
foo2(bool):
        sub     rsp,dil
        jne     .L9
        mov     edi,8
        ret
.L9:
        mov     edi,1
        call    exit_if_true(bool)

注意差异:

> xor eax,eax和ret被删除,因为现在编译器知道这是一个死代码.
>编译器交换了分支的顺序:现在首先是分支与puts调用,因此条件跳转可以更快(即使预测,未采用的分支也更快).

这里的假设是以noreturn函数调用或__builtin_unreachable结尾的分支将只执行一次或导致longjmp调用或异常抛出,这两种情况都很少见,并且在优化期间不需要优先处理.

您正在尝试将其用于不同的目的 – 通过提供有关别名的编译器信息(您可以尝试对齐进行相同操作).不幸的是,GCC不理解这种地址检查.

正如您所注意到的那样,添加__restrict__会有所帮助.所以__restrict__适用于别名,__ builtin_unreachable不适用.

请看以下使用__builtin_assume_aligned的示例:

void copy1(int *__restrict__ dst,const int *__restrict__ src)
{
    if (reinterpret_cast<uintptr_t>(dst) % 16 == 0) __builtin_unreachable();
    if (reinterpret_cast<uintptr_t>(src) % 16 == 0) __builtin_unreachable();

    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    dst[3] = src[3];
}

void copy2(int *__restrict__ dst,const int *__restrict__ src)
{
    dst = static_cast<int *>(__builtin_assume_aligned(dst,16));
    src = static_cast<const int *>(__builtin_assume_aligned(src,16));

    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    dst[3] = src[3];
}

生成的代码:

copy1(int*,int const*):
        movdqu  xmm0,XMMWORD PTR [rsi]
        movups  XMMWORD PTR [rdi],xmm0
        ret
copy2(int*,int const*):
        movdqa  xmm0,XMMWORD PTR [rsi]
        movaps  XMMWORD PTR [rdi],xmm0
        ret

您可以假设编译器可以理解dst%16 == 0表示指针是16字节对齐的,但事实并非如此.因此使用未对齐的存储和加载,而第二个版本生成更快的指令,需要对齐地址.

c – 如何实施“__builtin_va_list”?

c – 如何实施“__builtin_va_list”?

我想深入研究macOS上C语言中函数“printf”的实现. “printf”使用< stdarg.h>头文件.我打开< stdarg.h>文件并发现va_list只是一个宏.

那么,我真的好奇__builtin_va_list是如何实现的?我知道它是特定于编译器的.我在哪里可以找到__builtin_va_list的定义?我应该下载clang编译器的源代码吗?

解决方法

So,I am really curIoUs about how the __builtin_va_list is implemented?

__builtin_va_list在GCC编译器(或Clang/LLVM编译器)中实现.因此,您应该研究GCC编译器源代码以了解详细信息.

请看gcc/builtins.def& gcc/builtins.c更多.

我不熟悉Clang,它实现了相同的内置.

但是GCC和GCC都是Clang是开源或免费软件.它们是复杂的野兽(每行数百万行代码),因此您可能需要多年的工作才能理解它们.

请注意,编译器的ABI很重要.有关详细信息,请查看X86 psABI中的示例.

BTW,Grady Player评论说:

Pops the correct number of bytes off of the stack for each of those tokens…

不幸的是,今天它要复杂得多.在当前的处理器和ABI上,calling conventions确实使用processor registers来传递一些参数(而且细节中存在邪恶).

Should I download the source code of clang compiler?

是的,您还需要分配几年的工作来了解细节.

几年前,我确实编写了一些教程幻灯片和关于GCC实现的外部文档的链接,请参阅我的GCC MELT documentation页面(有点烂).

C++ 中的 __builtin_expect

C++ 中的 __builtin_expect

这个指令是 gcc 引入的,作用是允许程序员将最有可能执行的分支告诉编译器。这个指令的写法为:__builtin_expect(EXP, N)
意思是:EXP==N 的概率很大。

一般的使用方法是将__builtin_expect 指令封装为 likelyunlikely 宏。这两个宏的写法如下.

#define likely(x) __builtin_expect(!!(x), 1) //x很可能为真       
#define unlikely(x) __builtin_expect(!!(x), 0) //x很可能为假

内核中的 likely () 与 unlikely ()

首先要明确:

if(likely(value))  //等价于 if(value)
if(unlikely(value))  //也等价于 if(value)

__builtin_expect() 是 GCC (version>= 2.96)提供给程序员使用的,目的是将 “分支转移” 的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。
__builtin_expect((x),1) 表示 x 的值为真的可能性更大;
__builtin_expect((x),0) 表示 x 的值为假的可能性更大。
也就是说,使用 likely(),执行 if 后面的语句的机会更大,使用 unlikely(),执行 else 后面的语句的机会更大。通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。

例子

int x, y;
 if(unlikely(x > 0))
    y = 1; 
else 
    y = -1;

上面的代码中 gcc 编译的指令会预先读取 y = -1 这条指令,这适合 x 的值大于 0 的概率比较小的情况。如果 x 的值在大部分情况下是大于 0 的,就应该用 likely (x> 0),这样编译出的指令是预先读取 y = 1 这条指令了。这样系统在运行时就会减少重新取指了。

C++ 的位运算:__builtin, bitset

C++ 的位运算:__builtin, bitset

  • int __builtin_ffs (unsigned int x) 返回二进制表示中 x 的最后一位 $1$(最右边的)是从后向前第几位,比如 $7368(1110011001000)$ 返回 $4$ 。
  • int __builtin_clz (unsigned int x) 返回二进制表示中前导 $0$ 的个数。
  • int __builtin_ctz (unsigned int x) 返回二进制表示中末尾 $0$ 的个数。
  • int __builtin_popcount (unsigned int x) 返回二进制表示中 $1$ 的个数。
  • int __builtin_parity (unsigned int x) 返回 x 的奇偶校验位,也就是 x 的 $1$ 的个数模 $2$ 的结果。

这些函数都有相应的 unsigned longunsigned long long 版本,只需在函数名后面加上 lll 即可,如 int __builtin_clzll


bitset 定义在 <bitset> 库中。

  bitset<8> b1; // [0,0,0,0,0,0,0,0]
  bitset<8> b2(42);          // [0,0,1,0,1,0,1,0]
  bitset<17> bs(0xfff0);      // [1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0]
  string bit_string = "110010";
  bitset<8> b3(bit_string);       // [0,0,1,1,0,0,1,0]
  bitset<8> b4("110010");       // [0,0,1,1,0,0,1,0]

  cout << b4[0] << b4[1] << b4[2] << b4[3] << b4[4] << endl; // 0,1,0,0,1
  cout << b3 << endl; // 00110010 (1. 不是 50! 2. 会输出前导 0! )

  b4[0] = true; // b4 = [0,0,1,1,0,0,1,1]
  b4.set(3);    //      [0,0,1,1,1,0,1,1]
  b4.set(5);    //      [0,0,1,1,1,0,1,1] , 并没有变化
  b4.unset(4);  //      [0,0,1,0,1,0,1,1]
  b4.flip(1);   //      [0,0,1,0,1,0,0,1]
  b4.flip(1);   //      [0,0,1,0,1,0,1,1]
  b4.flip(2);   //      [0,0,1,0,1,1,1,1]
  b4.flip(0);   //      [0,0,1,0,1,1,1,0]

  cout << b2.size() << '','' << bs.size << endl;// 8,17
  cout << b2.count() << endl;// 3
  cout << bs.count() << endl;// 13

  string

另外,bitset 支持类似一个整数的操作,可以比较相等还是不等(但不能比较谁大谁小),可以左移右移,可以按位取与或非异或。但是一个 bitset 不能和一个真正的整数(如 int 型整数)进行这些操作

今天关于c – 为什么__builtin_prefetch在这里没有任何影响?为什么c++中用不了cin的讲解已经结束,谢谢您的阅读,如果想了解更多关于c – __builtin_unreachable有哪些优化方便?、c – 如何实施“__builtin_va_list”?、C++ 中的 __builtin_expect、C++ 的位运算:__builtin, bitset的相关知识,请在本站搜索。

本文标签: