加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – gcc是否用条件优化了我的周期?

发布时间:2020-12-16 03:11:46 所属栏目:百科 来源:网络整理
导读:我有以下周期: //condition will be set here to true or falsefor (int i = 0; i LARGE_NUMBER; i++) { if (condition) { //do foo } else { //do bar }} 假设:一个循环,如果没有条件比条件更快. (这是真的?) 问题:如果条件已经设定在循环周期之外,循环
我有以下周期:
//condition will be set here to true or false

for (int i = 0; i < LARGE_NUMBER; i++) {
    if (condition) {
        //do foo
    } else {
        //do bar
    }
}

假设:一个循环,如果没有条件比条件更快. (这是真的?)
问题:如果条件已经设定在循环周期之外,循环本身不接触条件,gcc是否会归因于我的?

如果没有,我应该切换if和for,重复的代码,违反DRY等.

解决方法

对于那些不想阅读冗长帖子的人来说,这个优化被称为(LLVM) Loop Unswitch.

为什么不问一个编译器?

void foo(char* c);

int main(int argc,char **argv) {
  bool const condition = argc % 2;

  for (int i = 0; i != argc; ++i) {
    if (condition) {
      foo(argv[1]);
    } else {
      foo(argv[0]);
    }
  }
  return 0; 
}

转换成SSA表格(通过LLVM try out):

define i32 @main(i32 %argc,i8** nocapture %argv) {
entry:
  %0 = icmp eq i32 %argc,0                       ; <i1> [#uses=1]
  br i1 %0,label %bb5,label %bb.nph

bb.nph:                                           ; preds = %entry
  %1 = and i32 %argc,1                           ; <i32> [#uses=1]
  %toBool = icmp eq i32 %1,0                     ; <i1> [#uses=1]
  %2 = getelementptr inbounds i8** %argv,i64 1   ; <i8**> [#uses=1]
  br i1 %toBool,label %bb3.us,label %bb3

bb3.us:                                           ; preds = %bb3.us,%bb.nph
  %i.07.us = phi i32 [ %4,%bb3.us ],[ 0,%bb.nph ] ; <i32> [#uses=1]
  %3 = load i8** %argv,align 8                   ; <i8*> [#uses=1]
  tail call void @_Z3fooPc(i8* %3)
  %4 = add nsw i32 %i.07.us,1                    ; <i32> [#uses=2]
  %exitcond = icmp eq i32 %4,%argc               ; <i1> [#uses=1]
  br i1 %exitcond,label %bb3.us

bb3:                                              ; preds = %bb3,%bb.nph
  %i.07 = phi i32 [ %6,%bb3 ],%bb.nph ]    ; <i32> [#uses=1]
  %5 = load i8** %2,align 8                      ; <i8*> [#uses=1]
  tail call void @_Z3fooPc(i8* %5)
  %6 = add nsw i32 %i.07,1                       ; <i32> [#uses=2]
  %exitcond8 = icmp eq i32 %6,%argc              ; <i1> [#uses=1]
  br i1 %exitcond8,label %bb3

bb5:                                              ; preds = %bb3,%bb3.us,%entry
  ret i32 0
}

不太可读,所以让我指出一下这里:

> entry:检查argc是否等于0,如果是,则转到bb5(exit),否则转到bb.nph
> bb.nph:计算条件的值,请转到bb3.us其他去bb3
> bb3.us和bb3:分别为true和false的循环
> bb5:退出

编译器几乎可以转换代码,只要效果与您所要求的相似.在这种情况下,它已经有效地将代码重写为:

int main(int argc,char**argv) {
  if (argc != 0)
  {
    int i = 0;
    if (argc % 2) {
      do {
        foo(argv[1]);
        ++i;
      } while (i != argc);
    } else {
      do {
        foo(argv[0]);
        ++i;
      } while (i != argc);
    }
  }
  return 0;
}

它是一种循环不变优化的形式,它与第一次检查相结合,以避免在不执行循环的情况下计算条件.

对于那些会认为第一个解决方案更清晰的人来说,我们很高兴让编译器为我们做最好的优化!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读