| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| ; For the following patterns: |
| ; umax(nuw_shl(z, x), nuw_shl(z, y)) -> nuw_shl(z, umax(x, y)) |
| ; umin(nuw_shl(z, x), nuw_shl(z, y)) -> nuw_shl(z, umin(x, y)) |
| ; umax(nuw_shl(x, z), nuw_shl(y, z)) -> nuw_shl(umax(x, y), z) |
| ; umin(nuw_shl(x, z), nuw_shl(y, z)) -> nuw_shl(umin(x, y), z) |
| |
| define i32 @umax_shl_common_lhs(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_rhs(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_rhs( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_common_lhs(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_lhs( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umin_shl_common_rhs(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_rhs( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umax_shl_common_lhs_const1(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs_const1( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 1, [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 1, %x |
| %shl_y = shl nuw i32 1, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_rhs_const1(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_rhs_const1( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], 1 |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, 1 |
| %shl_y = shl nuw i32 %y, 1 |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_common_lhs_const1(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_lhs_const1( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 1, [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 1, %x |
| %shl_y = shl nuw i32 1, %y |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umin_shl_common_rhs_const1(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_rhs_const1( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], 1 |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, 1 |
| %shl_y = shl nuw i32 %y, 1 |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| declare void @use(i8) |
| |
| define i32 @umax_shl_common_lhs_multi_use(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs_multi_use( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z]], [[X]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z]], [[Y]] |
| ; CHECK-NEXT: call void @use(i32 [[SHL_X]]) |
| ; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| call void @use(i32 %shl_x) |
| call void @use(i32 %shl_y) |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_rhs_multi_use(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_rhs_multi_use( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] |
| ; CHECK-NEXT: call void @use(i32 [[SHL_X]]) |
| ; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| call void @use(i32 %shl_x) |
| call void @use(i32 %shl_y) |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_common_lhs_multi_use(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_lhs_multi_use( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z]], [[X]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z]], [[Y]] |
| ; CHECK-NEXT: call void @use(i32 [[SHL_X]]) |
| ; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| call void @use(i32 %shl_x) |
| call void @use(i32 %shl_y) |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umin_shl_common_rhs_multi_use(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_rhs_multi_use( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] |
| ; CHECK-NEXT: call void @use(i32 [[SHL_X]]) |
| ; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| call void @use(i32 %shl_x) |
| call void @use(i32 %shl_y) |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umax_shl_common_lhs_commuted(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs_commuted( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 [[X]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_y, i32 %shl_x) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_rhs_commuted(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_rhs_commuted( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 [[X]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| %max = call i32 @llvm.umax.i32(i32 %shl_y, i32 %shl_x) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_common_lhs_commuted(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_lhs_commuted( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[Y]], i32 [[X]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %z, %x |
| %shl_y = shl nuw i32 %z, %y |
| %min = call i32 @llvm.umin.i32(i32 %shl_y, i32 %shl_x) |
| ret i32 %min |
| } |
| |
| define i32 @umin_shl_common_rhs_commuted(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_common_rhs_commuted( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[Y]], i32 [[X]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, %z |
| %shl_y = shl nuw i32 %y, %z |
| %min = call i32 @llvm.umin.i32(i32 %shl_y, i32 %shl_x) |
| ret i32 %min |
| } |
| |
| define <2 x i32> @umax_shl_common_lhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { |
| ; CHECK-LABEL: define <2 x i32> @umax_shl_common_lhs_vector( |
| ; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw <2 x i32> [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret <2 x i32> [[MAX]] |
| ; |
| %shl_x = shl nuw <2 x i32> %z, %x |
| %shl_y = shl nuw <2 x i32> %z, %y |
| %max = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) |
| ret <2 x i32> %max |
| } |
| |
| define <2 x i32> @umax_shl_common_rhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { |
| ; CHECK-LABEL: define <2 x i32> @umax_shl_common_rhs_vector( |
| ; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw <2 x i32> [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret <2 x i32> [[MAX]] |
| ; |
| %shl_x = shl nuw <2 x i32> %x, %z |
| %shl_y = shl nuw <2 x i32> %y, %z |
| %max = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) |
| ret <2 x i32> %max |
| } |
| |
| |
| define <2 x i32> @umin_shl_common_lhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { |
| ; CHECK-LABEL: define <2 x i32> @umin_shl_common_lhs_vector( |
| ; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw <2 x i32> [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret <2 x i32> [[MIN]] |
| ; |
| %shl_x = shl nuw <2 x i32> %z, %x |
| %shl_y = shl nuw <2 x i32> %z, %y |
| %min = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) |
| ret <2 x i32> %min |
| } |
| |
| define <2 x i32> @umin_shl_common_rhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { |
| ; CHECK-LABEL: define <2 x i32> @umin_shl_common_rhs_vector( |
| ; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) |
| ; CHECK-NEXT: [[MIN:%.*]] = shl nuw <2 x i32> [[TMP1]], [[Z]] |
| ; CHECK-NEXT: ret <2 x i32> [[MIN]] |
| ; |
| %shl_x = shl nuw <2 x i32> %x, %z |
| %shl_y = shl nuw <2 x i32> %y, %z |
| %min = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) |
| ret <2 x i32> %min |
| } |
| |
| ; Negative tests |
| |
| define i32 @umax_shl_different_lhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_different_lhs( |
| ; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z1]], [[X]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z2]], [[Y]] |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %z1, %x |
| %shl_y = shl nuw i32 %z2, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_different_rhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_different_rhs( |
| ; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z1]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z2]] |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, %z1 |
| %shl_y = shl nuw i32 %y, %z2 |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_different_lhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umin_shl_different_lhs( |
| ; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z1]], [[X]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z2]], [[Y]] |
| ; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %z1, %x |
| %shl_y = shl nuw i32 %z2, %y |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umin_shl_different_rhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umin_shl_different_rhs( |
| ; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z1]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z2]] |
| ; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, %z1 |
| %shl_y = shl nuw i32 %y, %z2 |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umax_shl_does_not_commute(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_does_not_commute( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, %y |
| %shl_y = shl nuw i32 %y, %z |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umin_shl_does_not_commute(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umin_shl_does_not_commute( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] |
| ; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MIN]] |
| ; |
| %shl_x = shl nuw i32 %x, %y |
| %shl_y = shl nuw i32 %y, %z |
| %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %min |
| } |
| |
| define i32 @umax_shl_common_lhs_no_nuw_flag(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs_no_nuw_flag( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl i32 2, [[X]] |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl i32 2, [[Y]] |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl i32 2, %x |
| %shl_y = shl i32 2, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_rhs_no_nuw_flag(i32 %x, i32 %y) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_rhs_no_nuw_flag( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { |
| ; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], 2 |
| ; CHECK-NEXT: [[SHL_Y:%.*]] = shl i32 [[Y]], 2 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw i32 %x, 2 |
| %shl_y = shl i32 %y, 2 |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |
| |
| define i32 @umax_shl_common_lhs_preserve_nsw(i32 %x, i32 %y, i32 %z) { |
| ; CHECK-LABEL: define i32 @umax_shl_common_lhs_preserve_nsw( |
| ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) |
| ; CHECK-NEXT: [[MAX:%.*]] = shl nuw nsw i32 [[Z]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[MAX]] |
| ; |
| %shl_x = shl nuw nsw i32 %z, %x |
| %shl_y = shl nuw nsw i32 %z, %y |
| %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) |
| ret i32 %max |
| } |