I was looking at one of the tests for the LLVM’s -loop-reroll
pass - llvm-project/basic.ll at main · llvm/llvm-project · GitHub
As in the test, the pass is able to take something like this -
; Function Attrs: nounwind sspstrong uwtable
define dso_local void @bar(ptr nocapture noundef readnone %0) local_unnamed_addr #0 {
br label %3
2: ; preds = %3
ret void
3: ; preds = %1, %3
%4 = phi i32 [ 0, %1 ], [ %10, %3 ]
%5 = tail call i32 @foo(i32 noundef %4) #2
%6 = add nuw nsw i32 %4, 1
%7 = tail call i32 @foo(i32 noundef %6) #2
%8 = add nuw nsw i32 %4, 2
%9 = tail call i32 @foo(i32 noundef %8) #2
%10 = add nuw nsw i32 %4, 3
%11 = icmp eq i32 %10, 500
br i1 %11, label %3, label %2, !llvm.loop !5
}
declare i32 @foo(i32 noundef) local_unnamed_addr #1
and perform a loop rerolling optimization on it.
But the given C code in the test that is expected to generate this LLVM IR -
int foo(int a);
void bar(int *x) {
for (int i = 0; i < 500; i += 3) {
foo(i);
foo(i+1);
foo(i+2);
}
}
instead generates (with clang) something akin to -
; Function Attrs: nounwind sspstrong uwtable
define dso_local void @bar(ptr nocapture noundef readnone %0) local_unnamed_addr #0 {
br label %3
2: ; preds = %3
ret void
3: ; preds = %1, %3
%4 = phi i32 [ 0, %1 ], [ %10, %3 ]
%5 = tail call i32 @foo(i32 noundef %4) #2
%6 = add nuw nsw i32 %4, 1
%7 = tail call i32 @foo(i32 noundef %6) #2
%8 = add nuw nsw i32 %4, 2
%9 = tail call i32 @foo(i32 noundef %8) #2
%10 = add nuw nsw i32 %4, 3
%11 = icmp ult i32 %4, 497
br i1 %11, label %3, label %2, !llvm.loop !5
}
declare i32 @foo(i32 noundef) local_unnamed_addr #1
which the loop rerolling pass is unable to work on (it looks like the pass is only able to work on icmp eq
llvm-project/LoopRerollPass.cpp at main · llvm/llvm-project · GitHub so this might be an expected result).
Note the difference:
In the test, we have - %11 = icmp eq i32 %10, 500
.
Clang generates - %11 = icmp ult i32 %4, 497
.
Is there a way for Clang to generate the former, so that the loop rerolling pass can work on the generated LLVM IR?