1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4target datalayout = "n32" 5 6define i1 @is_rem2_neg_i8(i8 %x) { 7; CHECK-LABEL: @is_rem2_neg_i8( 8; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -127 9; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], -127 10; CHECK-NEXT: ret i1 [[R]] 11; 12 %s = srem i8 %x, 2 13 %r = icmp slt i8 %s, 0 14 ret i1 %r 15} 16 17define <2 x i1> @is_rem2_pos_v2i8(<2 x i8> %x) { 18; CHECK-LABEL: @is_rem2_pos_v2i8( 19; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -127, i8 -127> 20; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 1, i8 1> 21; CHECK-NEXT: ret <2 x i1> [[R]] 22; 23 %s = srem <2 x i8> %x, <i8 2, i8 2> 24 %r = icmp sgt <2 x i8> %s, zeroinitializer 25 ret <2 x i1> %r 26} 27 28; i8 -97 == 159 == 0b10011111 29 30define i1 @is_rem32_pos_i8(i8 %x) { 31; CHECK-LABEL: @is_rem32_pos_i8( 32; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -97 33; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[TMP1]], 0 34; CHECK-NEXT: ret i1 [[R]] 35; 36 %s = srem i8 %x, 32 37 %r = icmp sgt i8 %s, 0 38 ret i1 %r 39} 40 41; i16 -32765 == 32771 == 0b1000000000000011 42 43define i1 @is_rem4_neg_i16(i16 %x) { 44; CHECK-LABEL: @is_rem4_neg_i16( 45; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[X:%.*]], -32765 46; CHECK-NEXT: [[R:%.*]] = icmp ugt i16 [[TMP1]], -32768 47; CHECK-NEXT: ret i1 [[R]] 48; 49 %s = srem i16 %x, 4 50 %r = icmp slt i16 %s, 0 51 ret i1 %r 52} 53 54declare void @use(i32) 55 56; TODO: This is still worth folding because srem is difficult? 57 58define i1 @is_rem32_neg_i32_extra_use(i32 %x) { 59; CHECK-LABEL: @is_rem32_neg_i32_extra_use( 60; CHECK-NEXT: [[S:%.*]] = srem i32 [[X:%.*]], 32 61; CHECK-NEXT: call void @use(i32 [[S]]) 62; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[S]], 0 63; CHECK-NEXT: ret i1 [[R]] 64; 65 %s = srem i32 %x, 32 66 call void @use(i32 %s) 67 %r = icmp slt i32 %s, 0 68 ret i1 %r 69} 70 71; Negative test - wrong compare constant 72 73define i1 @is_rem8_nonneg_i16(i16 %x) { 74; CHECK-LABEL: @is_rem8_nonneg_i16( 75; CHECK-NEXT: [[S:%.*]] = srem i16 [[X:%.*]], 8 76; CHECK-NEXT: [[R:%.*]] = icmp sgt i16 [[S]], -1 77; CHECK-NEXT: ret i1 [[R]] 78; 79 %s = srem i16 %x, 8 80 %r = icmp sgt i16 %s, -1 81 ret i1 %r 82} 83 84; Negative test - wrong remainder constant 85 86define i1 @is_rem3_neg_i8(i8 %x) { 87; CHECK-LABEL: @is_rem3_neg_i8( 88; CHECK-NEXT: [[S:%.*]] = srem i8 [[X:%.*]], 3 89; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[S]], 0 90; CHECK-NEXT: ret i1 [[R]] 91; 92 %s = srem i8 %x, 3 93 %r = icmp slt i8 %s, 0 94 ret i1 %r 95} 96 97; Negative test - wrong compare constant 98 99define i1 @is_rem16_something_i8(i8 %x) { 100; CHECK-LABEL: @is_rem16_something_i8( 101; CHECK-NEXT: [[S:%.*]] = srem i8 [[X:%.*]], 16 102; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[S]], 7 103; CHECK-NEXT: ret i1 [[R]] 104; 105 %s = srem i8 %x, 16 106 %r = icmp slt i8 %s, 7 107 ret i1 %r 108} 109 110; PR30281 - https://llvm.org/bugs/show_bug.cgi?id=30281 111 112; All of these tests contain foldable division-by-constant instructions, but we 113; can't assert that those folds have occurred before we process the later icmp. 114 115define i32 @icmp_div(i16 %a, i16 %c) { 116; CHECK-LABEL: @icmp_div( 117; CHECK-NEXT: entry: 118; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0 119; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]] 120; CHECK: then: 121; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0 122; CHECK-NEXT: [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32 123; CHECK-NEXT: br label [[EXIT]] 124; CHECK: exit: 125; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ] 126; CHECK-NEXT: ret i32 [[PHI]] 127; 128entry: 129 %tobool = icmp eq i16 %a, 0 130 br i1 %tobool, label %then, label %exit 131 132then: 133 %div = sdiv i16 %c, -1 134 %cmp = icmp ne i16 %div, 0 135 br label %exit 136 137exit: 138 %phi = phi i1 [ false, %entry ], [ %cmp, %then ] 139 %zext = zext i1 %phi to i32 140 %add = add nsw i32 %zext, -1 141 ret i32 %add 142} 143 144define i32 @icmp_div2(i16 %a, i16 %c) { 145; CHECK-LABEL: @icmp_div2( 146; CHECK-NEXT: entry: 147; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0 148; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]] 149; CHECK: then: 150; CHECK-NEXT: br label [[EXIT]] 151; CHECK: exit: 152; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ 0, [[THEN]] ] 153; CHECK-NEXT: ret i32 [[PHI]] 154; 155entry: 156 %tobool = icmp eq i16 %a, 0 157 br i1 %tobool, label %then, label %exit 158 159then: 160 %div = sdiv i16 %c, 0 161 %cmp = icmp ne i16 %div, 0 162 br label %exit 163 164exit: 165 %phi = phi i1 [ false, %entry ], [ %cmp, %then ] 166 %zext = zext i1 %phi to i32 167 %add = add nsw i32 %zext, -1 168 ret i32 %add 169} 170 171define i32 @icmp_div3(i16 %a, i16 %c) { 172; CHECK-LABEL: @icmp_div3( 173; CHECK-NEXT: entry: 174; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0 175; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]] 176; CHECK: then: 177; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0 178; CHECK-NEXT: [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32 179; CHECK-NEXT: br label [[EXIT]] 180; CHECK: exit: 181; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ] 182; CHECK-NEXT: ret i32 [[PHI]] 183; 184entry: 185 %tobool = icmp eq i16 %a, 0 186 br i1 %tobool, label %then, label %exit 187 188then: 189 %div = sdiv i16 %c, 1 190 %cmp = icmp ne i16 %div, 0 191 br label %exit 192 193exit: 194 %phi = phi i1 [ false, %entry ], [ %cmp, %then ] 195 %zext = zext i1 %phi to i32 196 %add = add nsw i32 %zext, -1 197 ret i32 %add 198} 199 200