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 } }
假设:没有条件而不是条件的周期更快。 (这是真的吗?)问题:如果condition
已经设置在for循环之外,并且循环本身没有触及condition
,那么gcc会将我的if
,if
如果没有,我应该切换if
和for
,重复代码,违反DRY等。
对于那些不想阅读冗长post的人来说,这种优化称为(在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; }
转换为SSAforms(通过LLVM试用 ):
define i32 @main(i32 %argc, i8** nocapture %argv) { entry: %0 = icmp eq i32 %argc, 0 ; [#uses=1] br i1 %0, label %bb5, label %bb.nph bb.nph: ; preds = %entry %1 = and i32 %argc, 1 ; [#uses=1] %toBool = icmp eq i32 %1, 0 ; [#uses=1] %2 = getelementptr inbounds i8** %argv, i64 1 ; [#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 ] ; [#uses=1] %3 = load i8** %argv, align 8 ; [#uses=1] tail call void @_Z3fooPc(i8* %3) %4 = add nsw i32 %i.07.us, 1 ; [#uses=2] %exitcond = icmp eq i32 %4, %argc ; [#uses=1] br i1 %exitcond, label %bb5, label %bb3.us bb3: ; preds = %bb3, %bb.nph %i.07 = phi i32 [ %6, %bb3 ], [ 0, %bb.nph ] ; [#uses=1] %5 = load i8** %2, align 8 ; [#uses=1] tail call void @_Z3fooPc(i8* %5) %6 = add nsw i32 %i.07, 1 ; [#uses=2] %exitcond8 = icmp eq i32 %6, %argc ; [#uses=1] br i1 %exitcond8, label %bb5, label %bb3 bb5: ; preds = %bb3, %bb3.us, %entry ret i32 0 }
也许不太可读,所以让我指出这里有什么:
-
entry
:检查argc
是否等于0,如果是,转到bb5
(退出)否则转到bb.nph
-
bb.nph
:计算condition
的值,如果是真的,转到bb3.us
else转到bb3.us
-
bb3.us
和bb3.us
:分别为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; }
它是循环不变优化的一种forms,这里结合第一次检查以避免在循环不会被执行时计算条件。
对于我们这些认为第一个解决方案更清晰的人来说,我们很高兴让编译器为我们进行细节优化!
如果在迭代期间可以certificatecondition
不会改变,那么任何体面的优化编译器都会这样做。
此外,即使编译器实际上没有这样做,您也可以支持您使用分析中的硬数据将代码重写为不太人类可读的forms的决定。 不要过早优化。 给代码的读者一个“嗯?”是不值得的。 为了减少几毫秒(和“读者”肯定包括你自己在未来的时间)的时刻。
我不主张通过通常的“过早优化”论点采取任何行动。 保持代码清晰是最重要的,如果整个程序太慢,您可能想要在程序彻底调试后分析并找到实际的瓶颈(通常无法猜测)。
即使编译器没有为您优化此特定情况,您可能想知道CPU执行某种forms的分支预测 ,这将大大减少在条件可预测的情况下处理条件所需的时间。
实际上, 管道中的大多数CPU处理指令以及必须确定跳转地址时,条件变量可能是未知的。 这将导致流水线停滞 ,这是大多数现代处理器试图猜测(事实上聪明)程序将跳转的地方。 如果条件变量确实已知(就像你的情况那样),猜测将是完美的。
所以我怀疑即使使用“哑”编译器,你也会看到这两个选项之间存在差异,至少在现代机器上是这样。