Đối với những người không muốn đọc một bài dài, tối ưu hóa này được gọi là (trong LLVM) Loop Unswitch.
Tại sao không yêu cầu trình biên dịch?
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;
}
được chuyển thành dạng SSA (thông qua 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
}
Không quá dễ đọc có lẽ, vì vậy hãy để tôi chỉ ra những gì ở đây:
entry
: kiểm tra nếu argc
bằng thành 0, nếu có, hãy truy cập bb5
(thoát) khác đi đến bb.nph
bb.nph
: tính giá trị của condition
, nếu đó là sự thật, đi đến bb3.us
khác đi đến bb3
bb3.us
và bb3
: vòng cho các điều kiện đúng và sai tương ứng
bb5
: exit
Một trình biên dịch có thể khá nhiều biến đổi mã của bạn như thế nào nó muốn, miễn là hiệu quả là tương tự như những gì bạn yêu cầu. Trong trường hợp này, nó đã có hiệu quả viết lại các mã như:
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;
}
Đó là một hình thức của Vòng Invariant Tối ưu hóa, kết hợp ở đây với một tấm séc đầu tiên để tránh tình trạng máy tính nếu vòng lặp sẽ không được thực thi.
Đối với những người trong chúng ta, những người sẽ nghĩ giải pháp đầu tiên là rõ ràng hơn, chúng tôi rất vui khi có trình biên dịch thực hiện tối ưu hóa nitty gritty cho chúng tôi!
nếu 'điều kiện' không thay đổi tại sao bạn đặt nó vào bên trong 'cho'? – nacho4d
@ nacho4d: Để tránh trùng lặp mã (tiêu đề 'for' và các câu lệnh khác ngoài' if' nhưng bên trong 'for') – erenon
Bạn có khai báo' điều kiện' là 'biến động 'không? – mvds