168 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 52; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4declare void @use(i8 %value);5 6; Since we know that any comparison of ucmp/scmp with a constant will result in7; a comparison of ucmp/scmp's operands, we can propagate such a comparison8; through the phi node and let the next iteration of instcombine simplify it.9define i1 @icmp_of_phi_of_scmp_with_constant(i1 %c, i16 %x, i16 %y)10; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant(11; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) {12; CHECK-NEXT: [[ENTRY:.*:]]13; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]14; CHECK: [[TRUE]]:15; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]16; CHECK-NEXT: br label %[[EXIT:.*]]17; CHECK: [[FALSE]]:18; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i16 [[Y]], [[X]]19; CHECK-NEXT: br label %[[EXIT]]20; CHECK: [[EXIT]]:21; CHECK-NEXT: [[R:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ]22; CHECK-NEXT: ret i1 [[R]]23;24{25entry:26 br i1 %c, label %true, label %false27true:28 %cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)29 br label %exit30false:31 %cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)32 br label %exit33exit:34 %phi = phi i8 [%cmp1, %true], [%cmp2, %false]35 %r = icmp slt i8 %phi, 036 ret i1 %r37}38 39; When one of the incoming values is ucmp/scmp and the other is not we can still perform the transformation40define i1 @icmp_of_phi_of_one_scmp_with_constant(i1 %c, i16 %x, i16 %y, i8 %false_val)41; CHECK-LABEL: define i1 @icmp_of_phi_of_one_scmp_with_constant(42; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[FALSE_VAL:%.*]]) {43; CHECK-NEXT: [[ENTRY:.*:]]44; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]45; CHECK: [[TRUE]]:46; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]47; CHECK-NEXT: br label %[[EXIT:.*]]48; CHECK: [[FALSE]]:49; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[FALSE_VAL]], 050; CHECK-NEXT: br label %[[EXIT]]51; CHECK: [[EXIT]]:52; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ]53; CHECK-NEXT: ret i1 [[PHI]]54;55{56entry:57 br i1 %c, label %true, label %false58true:59 %cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)60 br label %exit61false:62 br label %exit63exit:64 %phi = phi i8 [%cmp1, %true], [%false_val, %false]65 %r = icmp slt i8 %phi, 066 ret i1 %r67}68 69; Negative test: the RHS of comparison that uses the phi node is not constant70define i1 @icmp_of_phi_of_scmp_with_non_constant(i1 %c, i16 %x, i16 %y, i8 %cmp)71; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_non_constant(72; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[CMP:%.*]]) {73; CHECK-NEXT: [[ENTRY:.*:]]74; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]75; CHECK: [[TRUE]]:76; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]])77; CHECK-NEXT: br label %[[EXIT:.*]]78; CHECK: [[FALSE]]:79; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]])80; CHECK-NEXT: br label %[[EXIT]]81; CHECK: [[EXIT]]:82; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ]83; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], [[CMP]]84; CHECK-NEXT: ret i1 [[R]]85;86{87entry:88 br i1 %c, label %true, label %false89true:90 %cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)91 br label %exit92false:93 %cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)94 br label %exit95exit:96 %phi = phi i8 [%cmp1, %true], [%cmp2, %false]97 %r = icmp slt i8 %phi, %cmp98 ret i1 %r99}100 101; Negative test: more than one incoming value of the phi node is not one-use102define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use(i1 %c, i16 %x, i16 %y)103; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use(104; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) {105; CHECK-NEXT: [[ENTRY:.*:]]106; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]107; CHECK: [[TRUE]]:108; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]])109; CHECK-NEXT: call void @use(i8 [[CMP1]])110; CHECK-NEXT: br label %[[EXIT:.*]]111; CHECK: [[FALSE]]:112; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]])113; CHECK-NEXT: call void @use(i8 [[CMP2]])114; CHECK-NEXT: br label %[[EXIT]]115; CHECK: [[EXIT]]:116; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ]117; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], 0118; CHECK-NEXT: ret i1 [[R]]119;120{121entry:122 br i1 %c, label %true, label %false123true:124 %cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)125 call void @use(i8 %cmp1)126 br label %exit127false:128 %cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)129 call void @use(i8 %cmp2)130 br label %exit131exit:132 %phi = phi i8 [%cmp1, %true], [%cmp2, %false]133 %r = icmp slt i8 %phi, 0134 ret i1 %r135}136 137; Same as the first transformation, but the phi node uses the result of scmp twice. This verifies that we don't clone values more than once per block138define i1 @icmp_of_phi_of_scmp_with_constant_one_user_two_uses(i8 %c, i16 %x, i16 %y, i8 %false_val) {139; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant_one_user_two_uses(140; CHECK-SAME: i8 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[FALSE_VAL:%.*]]) {141; CHECK-NEXT: [[ENTRY:.*]]:142; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]143; CHECK-NEXT: switch i8 [[C]], label %[[BB_2:.*]] [144; CHECK-NEXT: i8 0, label %[[BB:.*]]145; CHECK-NEXT: i8 1, label %[[BB]]146; CHECK-NEXT: ]147; CHECK: [[BB_2]]:148; CHECK-NEXT: br label %[[BB]]149; CHECK: [[BB]]:150; CHECK-NEXT: [[R:%.*]] = phi i1 [ [[TMP0]], %[[ENTRY]] ], [ [[TMP0]], %[[ENTRY]] ], [ false, %[[BB_2]] ]151; CHECK-NEXT: ret i1 [[R]]152;153entry:154 %cmp = call i8 @llvm.scmp(i16 %x, i16 %y)155 switch i8 %c, label %bb_2 [156 i8 0, label %bb157 i8 1, label %bb158 ]159 160bb_2:161 br label %bb162 163bb:164 %phi = phi i8 [ %cmp, %entry ], [ %cmp, %entry ], [ 0, %bb_2 ]165 %r = icmp slt i8 %phi, 0166 ret i1 %r167}168