Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,10 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
return true;
}

if (match(U, m_IDiv(m_Value(), m_Specific(V))) &&
isValidAssumeForContext(cast<Instruction>(U), CtxI, DT))
Copy link
Member

Choose a reason for hiding this comment

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

isValidAssumeForContext assumes the first argument is an assume intrinsic. It is incorrect to pass a udiv.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, I am not sure of any other way to check for post-dominance.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe DT->dominates(cast<Instruction>(U), CtxI)? It guarantees we execute udiv before select. Then we can simplify the pattern in simplifySelectWithICmpCond.

Copy link
Member Author

@dc03 dc03 Sep 25, 2023

Choose a reason for hiding this comment

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

In this case, CtxI is always the icmp, so the dominates call will only work when the udiv dominates the icmp and not the other way round.

Copy link
Contributor

Choose a reason for hiding this comment

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

isValidAssumeForContext() should be fine to use for non-assumes as well. The key property of assumes here is that violating the fact results in immediate undefined behavior, which is also true for divisions.

Though I guess the isEphemeralValueOf() part of the function is only relevant for assumes...

Copy link
Member Author

Choose a reason for hiding this comment

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

@nikic Any issues that could occur with isEphemeralValueOf()?

return true;

// Consider only compare instructions uniquely controlling a branch
Value *RHS;
CmpInst::Predicate Pred;
Expand Down
54 changes: 54 additions & 0 deletions llvm/test/Analysis/ValueTracking/select-known-non-zero.ll
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,57 @@ define i1 @inv_select_v_sle_nonneg(i8 %v, i8 %C, i8 %y) {
%r = icmp eq i8 %s, 0
ret i1 %r
}

; Check udiv/sdiv occuring before icmp.
define i64 @incorrect_safe_div_1(i64 %n, i64 %d) {
; CHECK-LABEL: @incorrect_safe_div_1(
; CHECK-NEXT: [[TMP1:%.*]] = udiv i64 [[N:%.*]], [[D:%.*]]
; CHECK-NEXT: ret i64 [[TMP1]]
;
%1 = udiv i64 %n, %d
%2 = icmp eq i64 %d, 0
%3 = select i1 %2, i64 -1, i64 %1
ret i64 %3
}

; Check icmp occuring before udiv/sdiv.
define i64 @incorrect_safe_div_2(i64 %n, i64 %d) {
; CHECK-LABEL: @incorrect_safe_div_2(
; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[N:%.*]], [[D:%.*]]
; CHECK-NEXT: ret i64 [[TMP1]]
;
%1 = icmp eq i64 %d, 0
%2 = sdiv i64 %n, %d
%3 = select i1 %1, i64 -1, i64 %2
ret i64 %3
}

define i64 @incorrect_safe_div_call_1(i64 %n, i64 %d) {
; CHECK-LABEL: @incorrect_safe_div_call_1(
; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[N:%.*]], [[D:%.*]]
; CHECK-NEXT: tail call void @use(i64 [[D]])
; CHECK-NEXT: ret i64 [[TMP1]]
;
%1 = sdiv i64 %n, %d
tail call void @use(i64 %d)
%2 = icmp eq i64 %d, 0
%3 = select i1 %2, i64 -1, i64 %1
ret i64 %3
}

define i64 @incorrect_safe_div_call_2(i64 %n, i64 %d) {
; CHECK-LABEL: @incorrect_safe_div_call_2(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[D:%.*]], 0
; CHECK-NEXT: tail call void @use(i64 [[D]])
; CHECK-NEXT: [[TMP2:%.*]] = udiv i64 [[N:%.*]], [[D]]
; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 -1, i64 [[TMP2]]
; CHECK-NEXT: ret i64 [[TMP3]]
;
%1 = icmp eq i64 %d, 0
tail call void @use(i64 %d)
%2 = udiv i64 %n, %d
%3 = select i1 %1, i64 -1, i64 %2
ret i64 %3
}

declare void @use(i64)