Hi, folks. I work on a llvm issue and try to submit a patch.
It seems this discussion forum is more active, I want to repost the issue and receive more feedbacks.
define i16 @foo() {
entry:
br label %while.cond
while.cond: ; preds = %while.body.thread, %while.body, %entry
%i.0 = phi i16 [ 0, %entry ], [ %inc4, %while.body.thread ], [ %inc, %while.body ]
%j.0 = phi i16 [ 0, %entry ], [ %j.0, %while.body.thread ], [ %spec.select7, %while.body ]
%cmp = icmp slt i16 %i.0, 10
br i1 %cmp, label %while.body.thread, label %lor.end
while.body.thread: ; preds = %while.cond
%inc4 = add nsw i16 %i.0, 1
br label %while.cond, !llvm.loop !5
lor.end: ; preds = %while.cond
%cmp1.not = icmp eq i16 %j.0, 5
br i1 %cmp1.not, label %while.end, label %while.body
while.body: ; preds = %lor.end
%inc = add nuw nsw i16 %i.0, 1
%cmp2 = icmp eq i16 %inc, 12
%spec.select7 = select i1 %cmp2, i16 5, i16 %j.0
br label %while.cond, !llvm.loop !5
while.end: ; preds = %lor.end
ret i16 %i.0
}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
!0 = !{i32 7, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"wchar_size", i32 1}
!3 = !{i32 7, !"frame-pointer", i32 2}
!4 = !{!"clang version 16.0.0.prerel"}
!5 = distinct !{!5, !6}
!6 = !{!"llvm.loop.usefulinfo"}
The above loop is not in a canonical. It has a loop header (while.cond), an exit block (lor.end) and two latch blockes (while.body.thread, while.body).
The current implementation of LoopSimplify pass can transform it to a cannonical form.
define i16 @foo() {
entry:
br label %while.cond.outer
while.cond.outer: ; preds = %while.body, %entry
%i.0.ph = phi i16 [ %inc, %while.body ], [ 0, %entry ]
%j.0.ph = phi i16 [ %spec.select7, %while.body ], [ 0, %entry ]
br label %while.cond
while.cond: ; preds = %while.cond.outer, %while.body.thread
%i.0 = phi i16 [ %inc4, %while.body.thread ], [ %i.0.ph, %while.cond.outer ]
%cmp = icmp slt i16 %i.0, 10
br i1 %cmp, label %while.body.thread, label %lor.end
while.body.thread: ; preds = %while.cond
%inc4 = add nsw i16 %i.0, 1
br label %while.cond, !llvm.loop !5
lor.end: ; preds = %while.cond
%cmp1.not = icmp eq i16 %j.0.ph, 5
br i1 %cmp1.not, label %while.end, label %while.body
while.body: ; preds = %lor.end
%inc = add nuw nsw i16 %i.0, 1
%cmp2 = icmp eq i16 %inc, 12
%spec.select7 = select i1 %cmp2, i16 5, i16 %j.0.ph
br label %while.cond.outer, !llvm.loop !5
while.end: ; preds = %lor.end
ret i16 %i.0
}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
!0 = !{i32 7, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"wchar_size", i32 1}
!3 = !{i32 7, !"frame-pointer", i32 2}
!4 = !{!"clang version 16.0.0.prerel"}
!5 = distinct !{!5, !6}
!6 = !{!"llvm.loop.usefulinfo"}
“llvm.loop.usefulinfo” is a custom metadata which describe a special property.
Basically, it breaks while.cond block into two blockes while.cond and while.cond.outer and creates nested loops (single loop → nested two loops). Using a nested structure, each loop would only have a single latch block and loops become canonical form.
The question is how to preserve metadata attached to the original latch block’s teminator.
Option 1: Preserve all metadata for both loop
Many other passes handle metadata by preserving all of them. However, it might lead to incorrect behavior. In this case, after loop-simplify, the inner loop does not hold the property “llvm.loop.usefulinfo”. It applies to the outer loop only.
Option 2: Drop all metadata for both loop
This seems the most conservative method. But it might drop useful metadata such as “llvm.loop.unroll.disable”".
Option 3: Preserve metadata only for the outer loop
In the above example, after transformation, the inner loop could drop “llvm.loop.usefulinfo”. But I do not know if it could be generalized. Especially, if the inner loop becomes more complex.
Any suggestion is welcome.
@bjope @uabelho