Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions llvm/test/Transforms/InstCombine/freeze.ll
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,104 @@ exit: ; preds = %loop
ret void
}

; The recurrence for the GEP offset can't produce poison so the freeze should
; be pushed through to the ptr, but this is not currently supported.
define void @fold_phi_gep_phi_offset(ptr %init, ptr %end, i64 noundef %n) {
; CHECK-LABEL: @fold_phi_gep_phi_offset(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[I_NEXT_FR:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N:%.*]], [[ENTRY]] ], [ [[OFF_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
; CHECK-NEXT: [[I_NEXT:%.*]] = getelementptr i8, ptr [[I]], i64 [[OFF_NEXT]]
; CHECK-NEXT: [[I_NEXT_FR]] = freeze ptr [[I_NEXT]]
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[I_NEXT_FR]], [[END:%.*]]
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop

loop: ; preds = %loop, %entry
%i = phi ptr [ %init, %entry ], [ %i.next.fr, %loop ]
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
%off.next = shl i64 %off, 3
%i.next = getelementptr i8, ptr %i, i64 %off.next
%i.next.fr = freeze ptr %i.next
%cond = icmp eq ptr %i.next.fr, %end
br i1 %cond, label %loop, label %exit

exit: ; preds = %loop
ret void
}

; Offset is still guaranteed not to be poison, so the freeze could be moved
; here if we strip inbounds from the GEP, but this is not currently supported.
define void @fold_phi_gep_inbounds_phi_offset(ptr %init, ptr %end, i64 noundef %n) {
; CHECK-LABEL: @fold_phi_gep_inbounds_phi_offset(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[I_NEXT_FR:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N:%.*]], [[ENTRY]] ], [ [[OFF_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
; CHECK-NEXT: [[I_NEXT:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 [[OFF_NEXT]]
; CHECK-NEXT: [[I_NEXT_FR]] = freeze ptr [[I_NEXT]]
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[I_NEXT_FR]], [[END:%.*]]
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop

loop: ; preds = %loop, %entry
%i = phi ptr [ %init, %entry ], [ %i.next.fr, %loop ]
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
%off.next = shl i64 %off, 3
%i.next = getelementptr inbounds i8, ptr %i, i64 %off.next
%i.next.fr = freeze ptr %i.next
%cond = icmp eq ptr %i.next.fr, %end
br i1 %cond, label %loop, label %exit

exit: ; preds = %loop
ret void
}

; GEP can produce poison, check freeze isn't moved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly the freeze could be moved here too if we strip inbounds from the gep and push the freeze up to the pointer %i? The offset %off.next is still guaranteed not to be poison or undef I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly the freeze could be moved here too if we strip inbounds from the gep and push the freeze up to the pointer %i?

Yes I think so.

The offset %off.next is still guaranteed not to be poison or undef I think.

I don't believe so, %n needs to be marked noundef for that? I think this example is what you're referring to: https://godbolt.org/z/e8rGsz66W. Whereas Nikita wanted a test where the GEP can produce poison.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both variants probably have value. One requires just stripping poison, the other requires freezing an additional value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I've also added a test for the inbounds GEP + noundef offset variant

define void @cant_fold_phi_gep_phi_offset(ptr %init, ptr %end, i64 %n) {
; CHECK-LABEL: @cant_fold_phi_gep_phi_offset(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[I_NEXT_FR:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N:%.*]], [[ENTRY]] ], [ [[OFF_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
; CHECK-NEXT: [[I_NEXT:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 [[OFF_NEXT]]
; CHECK-NEXT: [[I_NEXT_FR]] = freeze ptr [[I_NEXT]]
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[I_NEXT_FR]], [[END:%.*]]
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop

loop: ; preds = %loop, %entry
%i = phi ptr [ %init, %entry ], [ %i.next.fr, %loop ]
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
%off.next = shl i64 %off, 3
%i.next = getelementptr inbounds i8, ptr %i, i64 %off.next
%i.next.fr = freeze ptr %i.next
%cond = icmp eq ptr %i.next.fr, %end
br i1 %cond, label %loop, label %exit

exit: ; preds = %loop
ret void
}

define void @fold_phi_multiple_insts(i32 %init, i32 %n) {
; CHECK-LABEL: @fold_phi_multiple_insts(
; CHECK-NEXT: entry:
Expand Down