前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >clang -O3 for循环的LLVM IR

clang -O3 for循环的LLVM IR

作者头像
racaljk
发布2018-08-31 11:10:33
1.2K0
发布2018-08-31 11:10:33
举报
文章被收录于专栏:racaljkracaljk

O3都是怪物,这里分析的是CLANG怪物,示例程序遍历数组每个元素然后放大。

代码语言:javascript
复制
void foreach_scale(int arr[],int elem){
    for(int i=0;i<elem;i++){
        arr[i] += (elem*1024);
    }
}

这里删去了用处不大的内容,只保留了关键的LLVM IR。通过分析可以看到,如果循环小于8 LLVM IR会使用vector,vector使用SIMD指令高效进行计算,如果大于8则是普通的for形式。

代码语言:javascript
复制
; Function Attrs: norecurse nounwind
define void @"\01?foreach_scale@@YAXQAHH@Z"(i32* nocapture %arr, i32 %elem) local_unnamed_addr #0 {
entry:
  ;elem>0则进入循环,否则整个函数结束
  %cmp5 = icmp sgt i32 %elem, 0
  br i1 %cmp5, label %for.body.lr.ph, label %for.cond.cleanup

for.body.lr.ph:                                  
  %mul = shl i32 %elem, 10;
  ; elem和8进行比较(utl表示unsigned less than)
  ; elem<8则跳到正常循环%for.body.preheader,否则跳到%vector.ph
  %min.iters.check = icmp ult i32 %elem, 8
  br i1 %min.iters.check, label %for.body.preheader, label %vector.ph

for.body.preheader:
  ;phi表示SSA里面的φ函数,详细参见LLVM DOC                          
  %i.06.ph = phi i32 [ 0, %for.body.lr.ph ], [ %n.vec, %middle.block ]
  br label %for.body

vector.ph:                                 
  %n.vec = and i32 %elem, -8
  ;首先构造<%mul val val val>,然后shufflevector构造<%mul %mul %mul %mul>
  %broadcast.splatinsert9 = insertelement <4 x i32> undef, i32 %mul, i32 0
  %broadcast.splat10 = shufflevector <4 x i32> %broadcast.splatinsert9, <4 x i32> undef, <4 x i32> zeroinitializer
  ;ditto, %broadcast.splatinsert9 == <%mul %mul %mul %mul>
  %broadcast.splatinsert11 = insertelement <4 x i32> undef, i32 %mul, i32 0
  %broadcast.splat12 = shufflevector <4 x i32> %broadcast.splatinsert11, <4 x i32> undef, <4 x i32> zeroinitializer
  br label %vector.body

vector.body:                                  
  %index = phi i32 [ 0, %vector.ph ], [ %index.next, %vector.body ]
  
  ;从arr指向的内存加载数据
  ;%0现在表示<arr[0] arr[1] arr[2] arr[3]>
  %0 = getelementoptr inbounds i32, i32* %arr, i32 %index
  %1 = bitcast i32* %0 to <4 x i32>*
  %wide.load = load <4 x i32>, <4 x i32>* %1, align 4, !tbaa !3

  ;%2表示<arr[4] arr[5] arr[6] arr[7]>
  %2 = getelementptr i32, i32* %0, i32 4
  %3 = bitcast i32* %2 to <4 x i32>*
  %wide.load8 = load <4 x i32>, <4 x i32>* %3, align 4, !tbaa !3

  ;<arr[0] arr[1] arr[2] arr[3]>与<%mul %mul %mul %mul>相加,得到vector:%4
  ;<arr[4] arr[5] arr[6] arr[7]>与<%mul %mul %mul %mul>相加,得到vector:%5
  %4 = add nsw <4 x i32> %wide.load, %broadcast.splat10
  %5 = add nsw <4 x i32> %wide.load8, %broadcast.splat12

  ;%4,%5写回内存
  %6 = bitcast i32* %0 to <4 x i32>*
  store <4 x i32> %4, <4 x i32>* %6, align 4, !tbaa !3
  %7 = bitcast i32* %2 to <4 x i32>*
  store <4 x i32> %5, <4 x i32>* %7, align 4, !tbaa !3
  
  %index.next = add i32 %index, 8
  %8 = icmp eq i32 %index.next, %n.vec
  br i1 %8, label %middle.block, label %vector.body, !llvm.loop !7

middle.block:                                   
  %cmp.n = icmp eq i32 %n.vec, %elem
  br i1 %cmp.n, label %for.cond.cleanup, label %for.body.preheader

;函数返回
for.cond.cleanup:                               
  ret void

for.body:                                       
  %i.06 = phi i32 [ %inc, %for.body ], [ %i.06.ph, %for.body.preheader ]‘
  ; arr[i] = arr[i]+ (elem*1024),其中%mul=(elem*1024)
  %arrayidx = getelementptr inbounds i32, i32* %arr, i32 %i.06
  %9 = load i32, i32* %arrayidx, align 4, !tbaa !3
  %add = add nsw i32 %9, %mul
  store i32 %add, i32* %arrayidx, align 4, !tbaa !3
  ; i++
  %inc = add nuw nsw i32 %i.06, 1
  ; 循环条件i<elem判断
  %exitcond = icmp eq i32 %inc, %elem
  br i1 %exitcond, label %for.cond.cleanup, label %for.body, !llvm.loop !10
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-08-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档