gcc是否优化我的循环条件? [英] Does gcc optimize my cycle with condition?

查看:114
本文介绍了gcc是否优化我的循环条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下循环:

//condition will be set here to true or false

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

假设:如果没有条件,条件。 (这是真的吗?)
问题:如果,如果条件已设置,在循环之外,并且循环本身不触及条件

Assumption: A cycle if faster without a condition than with a condition. (Is this true?) Question: Will gcc factor out my if, if condition has been set outside the for cycle, and the cycle itself doesn't touch condition?

如果没有,我应该切换如果代表,重复代码,违反DRY等。

If not, I should switch the if and the for, duplicate code, violate DRY, etc.

推荐答案

对于那些不想读长篇文章的人来说,这个优化被称为(在LLVM中)

For those who don't wish to read a lengthy post, this optimization is called (in 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试用):

Is transformed into SSA form (via 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 %bb5, label %bb3.us

bb3:                                              ; preds = %bb3, %bb.nph
  %i.07 = phi i32 [ %6, %bb3 ], [ 0, %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 %bb5, label %bb3

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

也不太可读,所以让我指出这里是什么:

Not too readable perhaps, so let me point out what's here:


  • c>:检查 argc 等于0,如果是,转到 bb5 bb.nph

  • bb.nph :计算 condition ,如果为真,请转到 bb3.us 否则转到 bb3

  • bb3.us bb3 假条件。

  • bb5 :exit

  • entry: check if argc is equal to 0, if it is, go to bb5 (exit) else go to bb.nph
  • bb.nph: compute the value of condition, if it's true, go to bb3.us else go to bb3
  • bb3.us and bb3: loops for the true and false condition respectively
  • bb5: exit

编译器可以很大程度上改变你的代码如何,只要效果类似于你所要求的。在这种情况下,它有效地将代码重写为:

A compiler can pretty much transform your code how it wants, as long as the effect is similar to what you asked for. In this case, it has effectively rewritten the code as:

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;
}

这是循环不变优化的一种形式,计算条件如果循环不会被执行。

It's a form of Loop Invariant Optimization, combined here with a first check to avoid computing the condition if the loop is not going to get executed.

对于那些认为第一个解决方案更清楚的人,我们很高兴有编译器为我们做细致的优化!

For those of us who would think the first solution is clearer, we're quite happy to have the compiler do the nitty gritty optimization for us!

这篇关于gcc是否优化我的循环条件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆