1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4; https://alive2.llvm.org/ce/z/5eCiWi 5define i8 @urem_assume(i8 %x, i8 %n) { 6; CHECK-LABEL: @urem_assume( 7; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] 8; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] 9; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) 10; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 11; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[N]] 12; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] 13; CHECK-NEXT: ret i8 [[OUT]] 14; 15 %cmp = icmp ult i8 %x, %n 16 tail call void @llvm.assume(i1 %cmp) 17 %add = add nuw i8 %x, 1 18 %out = urem i8 %add, %n 19 ret i8 %out 20} 21 22; https://alive2.llvm.org/ce/z/MGgtYN 23define i8 @urem_assume_without_nuw(i8 %x, i8 %n) { 24; CHECK-LABEL: @urem_assume_without_nuw( 25; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] 26; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] 27; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) 28; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 29; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[N]] 30; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] 31; CHECK-NEXT: ret i8 [[OUT]] 32; 33 %cmp = icmp ult i8 %x, %n 34 tail call void @llvm.assume(i1 %cmp) 35 %add = add i8 %x, 1 36 %out = urem i8 %add, %n 37 ret i8 %out 38} 39 40; Negative test: The assume is false 41define i8 @urem_assume_eq(i8 %x, i8 %n) { 42; CHECK-LABEL: @urem_assume_eq( 43; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[N:%.*]] 44; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) 45; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 1 46; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] 47; CHECK-NEXT: ret i8 [[OUT]] 48; 49 %cmp = icmp eq i8 %x, %n 50 tail call void @llvm.assume(i1 %cmp) 51 %add = add i8 %x, 1 52 %out = urem i8 %add, %n 53 ret i8 %out 54} 55 56; Negative test: The assume is false 57define i8 @urem_assume_ne(i8 %x, i8 %n) { 58; CHECK-LABEL: @urem_assume_ne( 59; CHECK-NEXT: start: 60; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], [[N:%.*]] 61; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) 62; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 1 63; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] 64; CHECK-NEXT: ret i8 [[OUT]] 65; 66start: 67 %cmp = icmp ne i8 %x, %n 68 tail call void @llvm.assume(i1 %cmp) 69 %add = add i8 %x, 1 70 %out = urem i8 %add, %n 71 ret i8 %out 72} 73 74; Negative test: The add constant is not 1 75define i8 @urem_assume_with_unexpected_const(i8 %x, i8 %n) { 76; CHECK-LABEL: @urem_assume_with_unexpected_const( 77; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X:%.*]], [[N:%.*]] 78; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) 79; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 2 80; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] 81; CHECK-NEXT: ret i8 [[OUT]] 82; 83 %cmp = icmp ult i8 %x, %n 84 tail call void @llvm.assume(i1 %cmp) 85 %add = add i8 %x, 2 ; Transform only when the constant is 1 86 %out = urem i8 %add, %n 87 ret i8 %out 88} 89 90; https://alive2.llvm.org/ce/z/gNhZ2x 91define i8 @urem_without_assume(i8 %arg, i8 %arg2) { 92; CHECK-LABEL: @urem_without_assume( 93; CHECK-NEXT: [[X:%.*]] = urem i8 [[ARG:%.*]], [[ARG2:%.*]] 94; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X]] 95; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 96; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[ARG2]] 97; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] 98; CHECK-NEXT: ret i8 [[OUT]] 99; 100 %x = urem i8 %arg, %arg2 101 %add = add i8 %x, 1 102 %out = urem i8 %add, %arg2 103 ret i8 %out 104} 105 106; https://alive2.llvm.org/ce/z/eHkgRa 107define i8 @urem_with_dominating_condition(i8 %x, i8 %n) { 108; CHECK-LABEL: @urem_with_dominating_condition( 109; CHECK-NEXT: start: 110; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] 111; CHECK-NEXT: [[COND:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] 112; CHECK-NEXT: br i1 [[COND]], label [[DOTBB0:%.*]], label [[DOTBB1:%.*]] 113; CHECK: .bb0: 114; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 115; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i8 [[ADD]], [[N]] 116; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP0]], i8 0, i8 [[ADD]] 117; CHECK-NEXT: ret i8 [[OUT]] 118; CHECK: .bb1: 119; CHECK-NEXT: ret i8 0 120; 121start: 122 %cond = icmp ult i8 %x, %n 123 br i1 %cond, label %.bb0, label %.bb1 ; Should also works for a dominating condition 124.bb0: 125 %add = add i8 %x, 1 126 %out = urem i8 %add, %n 127 ret i8 %out 128.bb1: 129 ret i8 0 130} 131 132; Revert the dominating condition and target branch at the same time. 133define i8 @urem_with_dominating_condition_false(i8 %x, i8 %n) { 134; CHECK-LABEL: @urem_with_dominating_condition_false( 135; CHECK-NEXT: start: 136; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] 137; CHECK-NEXT: [[COND_NOT:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] 138; CHECK-NEXT: br i1 [[COND_NOT]], label [[DOTBB0:%.*]], label [[DOTBB1:%.*]] 139; CHECK: .bb0: 140; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 141; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i8 [[ADD]], [[N]] 142; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP0]], i8 0, i8 [[ADD]] 143; CHECK-NEXT: ret i8 [[OUT]] 144; CHECK: .bb1: 145; CHECK-NEXT: ret i8 0 146; 147start: 148 %cond = icmp uge i8 %x, %n 149 br i1 %cond, label %.bb1, label %.bb0 ; Swap the branch targets 150.bb0: 151 %add = add i8 %x, 1 152 %out = urem i8 %add, %n 153 ret i8 %out 154.bb1: 155 ret i8 0 156} 157 158; Negative test 159define noundef i8 @urem_with_opposite_condition(i8 %x, i8 %n) { 160; CHECK-LABEL: @urem_with_opposite_condition( 161; CHECK-NEXT: [[COND:%.*]] = icmp ult i8 [[X:%.*]], [[N:%.*]] 162; CHECK-NEXT: br i1 [[COND]], label [[DOTBB1:%.*]], label [[DOTBB0:%.*]] 163; CHECK: .bb0: 164; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 1 165; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] 166; CHECK-NEXT: ret i8 [[OUT]] 167; CHECK: .bb1: 168; CHECK-NEXT: ret i8 0 169; 170 %cond = icmp ult i8 %x, %n 171 br i1 %cond, label %.bb1, label %.bb0 ; Revert the condition 172.bb0: 173 %add = add i8 %x, 1 174 %out = urem i8 %add, %n 175 ret i8 %out 176.bb1: 177 ret i8 0 178} 179 180declare void @llvm.assume(i1 noundef) 181