| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| ; Test that foldICmpDivConstant can treat sdiv as udiv when the dividend |
| ; is known non-negative (e.g. via a dominating condition), allowing the |
| ; fold to proceed despite a signed div / unsigned icmp mismatch. |
| ; Non-power-of-two divisors are used to prevent sdiv->lshr conversion. |
| ; The sdiv is placed in the entry block where x's sign is unknown, and |
| ; the icmp is in a block dominated by a condition that proves x >= 0. |
| |
| declare void @use(i32) |
| |
| ; Positive test: x > 255 dominates the icmp, proving x non-negative. |
| ; sdiv(x, 65) = udiv(x, 65) when x >= 0, and udiv(x, 65) > 2 when x >= 195. |
| ; Since x > 255 >= 195, the result folds to true. |
| define i1 @icmp_sdiv_domcond(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_domcond( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: ret i1 true |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = sdiv i32 %x, 65 |
| call void @use(i32 %div) |
| %cond = icmp sgt i32 %x, 255 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Positive test: add+sdiv pattern (mirrors real-world kernel case). |
| ; x+63 > 255 dominates the icmp, proving x+63 non-negative. |
| define i1 @icmp_add_sdiv_domcond(i32 %x) { |
| ; CHECK-LABEL: @icmp_add_sdiv_domcond( |
| ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 63 |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[ADD]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[ADD]], 255 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: ret i1 true |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %add = add i32 %x, 63 |
| %div = sdiv i32 %add, 65 |
| call void @use(i32 %div) |
| %cond = icmp sgt i32 %add, 255 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Positive test: udiv case (no signedness mismatch, baseline behavior). |
| define i1 @icmp_udiv_domcond(i32 %x) { |
| ; CHECK-LABEL: @icmp_udiv_domcond( |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp ugt i32 [[X]], 255 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: ret i1 true |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = udiv i32 %x, 65 |
| call void @use(i32 %div) |
| %cond = icmp ugt i32 %x, 255 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Negative test: dominating condition is too weak. |
| ; x > 127 does NOT prove sdiv(x, 65) > 2 (e.g. x=128, sdiv(128,65)=1). |
| define i1 @icmp_sdiv_domcond_too_weak(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_domcond_too_weak( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 127 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 194 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = sdiv i32 %x, 65 |
| call void @use(i32 %div) |
| %cond = icmp sgt i32 %x, 127 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Negative test: no dominating condition, x's sign is unknown. |
| define i1 @icmp_sdiv_no_domcond(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_no_domcond( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %div = sdiv i32 %x, 65 |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| } |
| |
| ; Negative test: comparison is on the boundary. |
| ; x > 194 means x >= 195, sdiv(195, 65) = 3, but 3 > 3 is false. |
| define i1 @icmp_sdiv_domcond_boundary(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_domcond_boundary( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 194 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 259 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = sdiv i32 %x, 65 |
| call void @use(i32 %div) |
| %cond = icmp sgt i32 %x, 194 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 3 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Negative test: dividend is known negative, sdiv != udiv. |
| define i1 @icmp_sdiv_negative_dividend(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_negative_dividend( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X]], -100 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = sdiv i32 %x, 65 |
| call void @use(i32 %div) |
| %cond = icmp slt i32 %x, -100 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |
| |
| ; Negative test: divisor is negative, sdiv(x, -65) != udiv(x, -65). |
| define i1 @icmp_sdiv_negative_divisor(i32 %x) { |
| ; CHECK-LABEL: @icmp_sdiv_negative_divisor( |
| ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], -65 |
| ; CHECK-NEXT: call void @use(i32 [[DIV]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255 |
| ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %div = sdiv i32 %x, -65 |
| call void @use(i32 %div) |
| %cond = icmp sgt i32 %x, 255 |
| br i1 %cond, label %if.true, label %if.false |
| |
| if.true: |
| %cmp = icmp samesign ugt i32 %div, 2 |
| ret i1 %cmp |
| |
| if.false: |
| ret i1 false |
| } |