首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么clang忽略__restrict__?

为什么clang忽略__restrict__?
EN

Stack Overflow用户
提问于 2018-05-16 07:48:45
回答 1查看 2.8K关注 0票数 10

我刚刚测试了一个小示例,以检查__restrict__在最新编译器上是否在C++中工作:

代码语言:javascript
复制
void foo(int x,int* __restrict__ ptr1, int& v2) {
   for(int i=0;i<x;i++) {
       if(*ptr1==v2) {
           ++ptr1;
       } else {
           *ptr1=*ptr1+1;
       }
   }
}

当在godbolt.org上使用最新的gcc (gcc8.1 -O3 -std=c++14)尝试它时,__restrict__按预期工作:v2只加载一次,因为它不能使用ptr1别名。

以下是相关的装配部件:

代码语言:javascript
复制
.L5:
  mov eax, DWORD PTR [rsi]
  cmp eax, ecx # <-- ecx contains v2, no load from memory
  jne .L3
  add edx, 1
  add rsi, 4
  cmp edi, edx
  jne .L5

现在,最新的clang (clang6.0.0 -O3 -std=c++14)也是如此。它只展开一次循环,因此生成的代码要大得多,但是下面是要点:

代码语言:javascript
复制
.LBB0_3: # =>This Inner Loop Header: Depth=1
  mov edi, dword ptr [rsi]
  cmp edi, dword ptr [rdx] # <-- restrict didn't work, v2 loaded from memory in hot loop
  jne .LBB0_9
  add rsi, 4
  mov edi, dword ptr [rsi]
  cmp edi, dword ptr [rdx] # <-- restrict didn't work, v2 loaded from memory in hot loop
  je .LBB0_12

为什么是这种情况?我知道__restrict__是不标准的,编译器可以随意忽略它,但是它似乎是从代码中获取最后一点性能的一种非常基本的技术,所以我怀疑clang在支持和忽略关键字本身的同时并不支持它。那么,这里有什么问题呢?我做错什么了吗?

EN

回答 1

Stack Overflow用户

发布于 2018-10-29 16:36:14

这么多没用的评论..。

这似乎是Clang别名分析器中的一个bug。如果您将v2类型更改为short编译器,则可以根据基于类型的别名规则从循环中愉快地删除它:

代码语言:javascript
复制
for.body:                                         ; preds = %for.inc, %for.body.lr.ph
  %i.09 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
  %ptr1.addr.08 = phi i32* [ %ptr1, %for.body.lr.ph ], [ %ptr1.addr.1, %for.inc ]
  %1 = load i32, i32* %ptr1.addr.08, align 4, !tbaa !5
  %cmp1 = icmp eq i32 %1, %conv
  br i1 %cmp1, label %if.then, label %if.else

但是对于原始循环,两个内存引用的别名集是相同的,这就是为什么中间端不能优化它的原因:

代码语言:javascript
复制
  %i.08 = phi i32 [ %inc, %for.inc ], [ 0, %for.body.preheader ]
  %ptr1.addr.07 = phi i32* [ %ptr1.addr.1, %for.inc ], [ %ptr1, %for.body.preheader ]
  %0 = load i32, i32* %ptr1.addr.07, align 4, !tbaa !1
  %1 = load i32, i32* %v2, align 4, !tbaa !1
  %cmp1 = icmp eq i32 %0, %1
  br i1 %cmp1, label %if.then, label %if.else

请注意附加到两个内存引用的!tbaa !1,这意味着编译器无法区分它们中的任何一个访问的内存。似乎restrict注释已经丢失了。

我鼓励您使用最新的Clang来复制它,并在LLVM Bugzilla中提交一个bug (一定要抄送哈尔芬克尔)。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50365141

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档