; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -passes=instcombine < %s | FileCheck %s declare i8 @llvm.umin.i8(i8, i8) declare i8 @llvm.umax.i8(i8, i8) declare i8 @llvm.smin.i8(i8, i8) declare i8 @llvm.smax.i8(i8, i8) declare <3 x i8> @llvm.umin.v3i8(<3 x i8>, <3 x i8>) declare <3 x i8> @llvm.umax.v3i8(<3 x i8>, <3 x i8>) declare <3 x i8> @llvm.smin.v3i8(<3 x i8>, <3 x i8>) declare <3 x i8> @llvm.smax.v3i8(<3 x i8>, <3 x i8>) declare void @use(i8) declare void @use_vec(<3 x i8>) define i8 @umin_known_bits(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_known_bits( ; CHECK-NEXT: ret i8 0 ; %x2 = and i8 %x, 127 %m = call i8 @llvm.umin.i8(i8 %x2, i8 %y) %r = and i8 %m, -128 ret i8 %r } define i8 @umax_known_bits(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_known_bits( ; CHECK-NEXT: ret i8 -128 ; %x2 = or i8 %x, -128 %m = call i8 @llvm.umax.i8(i8 %x2, i8 %y) %r = and i8 %m, -128 ret i8 %r } define i8 @smin_known_bits(i8 %x, i8 %y) { ; CHECK-LABEL: @smin_known_bits( ; CHECK-NEXT: ret i8 -128 ; %x2 = or i8 %x, -128 %m = call i8 @llvm.smin.i8(i8 %x2, i8 %y) %r = and i8 %m, -128 ret i8 %r } define i8 @smax_known_bits(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_known_bits( ; CHECK-NEXT: ret i8 0 ; %x2 = and i8 %x, 127 %m = call i8 @llvm.smax.i8(i8 %x2, i8 %y) %r = and i8 %m, -128 ret i8 %r } define i8 @smax_sext(i5 %x, i5 %y) { ; CHECK-LABEL: @smax_sext( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smax.i5(i5 [[X:%.*]], i5 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %sx = sext i5 %x to i8 %sy = sext i5 %y to i8 %m = call i8 @llvm.smax.i8(i8 %sx, i8 %sy) ret i8 %m } ; Extra use is ok. define i8 @smin_sext(i5 %x, i5 %y) { ; CHECK-LABEL: @smin_sext( ; CHECK-NEXT: [[SY:%.*]] = sext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[SY]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smin.i5(i5 [[X:%.*]], i5 [[Y]]) ; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %sx = sext i5 %x to i8 %sy = sext i5 %y to i8 call void @use(i8 %sy) %m = call i8 @llvm.smin.i8(i8 %sx, i8 %sy) ret i8 %m } ; Sext doesn't change unsigned min/max comparison of narrow values. define i8 @umax_sext(i5 %x, i5 %y) { ; CHECK-LABEL: @umax_sext( ; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[SX]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umax.i5(i5 [[X]], i5 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %sx = sext i5 %x to i8 call void @use(i8 %sx) %sy = sext i5 %y to i8 %m = call i8 @llvm.umax.i8(i8 %sx, i8 %sy) ret i8 %m } define <3 x i8> @umin_sext(<3 x i5> %x, <3 x i5> %y) { ; CHECK-LABEL: @umin_sext( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.umin.v3i5(<3 x i5> [[X:%.*]], <3 x i5> [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sext <3 x i5> [[TMP1]] to <3 x i8> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %sx = sext <3 x i5> %x to <3 x i8> %sy = sext <3 x i5> %y to <3 x i8> %m = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %m } ; Negative test - zext may change sign of inputs define i8 @smax_zext(i5 %x, i5 %y) { ; CHECK-LABEL: @smax_zext( ; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[ZX]], i8 [[ZY]]) ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i5 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.smax.i8(i8 %zx, i8 %zy) ret i8 %m } ; Negative test - zext may change sign of inputs define i8 @smin_zext(i5 %x, i5 %y) { ; CHECK-LABEL: @smin_zext( ; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[ZX]], i8 [[ZY]]) ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i5 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.smin.i8(i8 %zx, i8 %zy) ret i8 %m } define i8 @umax_zext(i5 %x, i5 %y) { ; CHECK-LABEL: @umax_zext( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umax.i5(i5 [[X:%.*]], i5 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i5 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.umax.i8(i8 %zx, i8 %zy) ret i8 %m } define i8 @umin_zext(i5 %x, i5 %y) { ; CHECK-LABEL: @umin_zext( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umin.i5(i5 [[X:%.*]], i5 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i5 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.umin.i8(i8 %zx, i8 %zy) ret i8 %m } ; Negative test - mismatched types define i8 @umin_zext_types(i6 %x, i5 %y) { ; CHECK-LABEL: @umin_zext_types( ; CHECK-NEXT: [[ZX:%.*]] = zext i6 [[X:%.*]] to i8 ; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[ZX]], i8 [[ZY]]) ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i6 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.umin.i8(i8 %zx, i8 %zy) ret i8 %m } ; Negative test - mismatched extends define i8 @umin_ext(i5 %x, i5 %y) { ; CHECK-LABEL: @umin_ext( ; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[SX]], i8 [[ZY]]) ; CHECK-NEXT: ret i8 [[M]] ; %sx = sext i5 %x to i8 %zy = zext i5 %y to i8 %m = call i8 @llvm.umin.i8(i8 %sx, i8 %zy) ret i8 %m } ; Negative test - too many uses. define i8 @umin_zext_uses(i5 %x, i5 %y) { ; CHECK-LABEL: @umin_zext_uses( ; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[ZX]]) ; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[ZY]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[ZX]], i8 [[ZY]]) ; CHECK-NEXT: ret i8 [[M]] ; %zx = zext i5 %x to i8 call void @use(i8 %zx) %zy = zext i5 %y to i8 call void @use(i8 %zy) %m = call i8 @llvm.umin.i8(i8 %zx, i8 %zy) ret i8 %m } define i8 @smax_sext_constant(i5 %x) { ; CHECK-LABEL: @smax_sext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smax.i5(i5 [[X:%.*]], i5 7) ; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %e = sext i5 %x to i8 %m = call i8 @llvm.smax.i8(i8 %e, i8 7) ret i8 %m } ; simplifies define i8 @smax_sext_constant_big(i5 %x) { ; CHECK-LABEL: @smax_sext_constant_big( ; CHECK-NEXT: ret i8 16 ; %e = sext i5 %x to i8 %m = call i8 @llvm.smax.i8(i8 %e, i8 16) ret i8 %m } ; negative test define i8 @smax_zext_constant(i5 %x) { ; CHECK-LABEL: @smax_zext_constant( ; CHECK-NEXT: [[E:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[E]], i8 7) ; CHECK-NEXT: ret i8 [[M]] ; %e = zext i5 %x to i8 %m = call i8 @llvm.smax.i8(i8 %e, i8 7) ret i8 %m } define <3 x i8> @smin_sext_constant(<3 x i5> %x) { ; CHECK-LABEL: @smin_sext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.smin.v3i5(<3 x i5> [[X:%.*]], <3 x i5> <i5 7, i5 15, i5 -16>) ; CHECK-NEXT: [[M:%.*]] = sext <3 x i5> [[TMP1]] to <3 x i8> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %e = sext <3 x i5> %x to <3 x i8> %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %e, <3 x i8> <i8 7, i8 15, i8 -16>) ret <3 x i8> %m } ; negative test define i8 @smin_zext_constant(i5 %x) { ; CHECK-LABEL: @smin_zext_constant( ; CHECK-NEXT: [[E:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[E]], i8 7) ; CHECK-NEXT: ret i8 [[M]] ; %e = zext i5 %x to i8 %m = call i8 @llvm.smin.i8(i8 %e, i8 7) ret i8 %m } define i8 @umax_sext_constant(i5 %x) { ; CHECK-LABEL: @umax_sext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umax.i5(i5 [[X:%.*]], i5 7) ; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %e = sext i5 %x to i8 %m = call i8 @llvm.umax.i8(i8 %e, i8 7) ret i8 %m } ; negative test define i8 @umax_sext_constant_big(i5 %x) { ; CHECK-LABEL: @umax_sext_constant_big( ; CHECK-NEXT: [[E:%.*]] = sext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[E]], i8 126) ; CHECK-NEXT: ret i8 [[M]] ; %e = sext i5 %x to i8 %m = call i8 @llvm.umax.i8(i8 %e, i8 126) ret i8 %m } define <3 x i8> @umax_zext_constant(<3 x i5> %x) { ; CHECK-LABEL: @umax_zext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.umax.v3i5(<3 x i5> [[X:%.*]], <3 x i5> <i5 7, i5 15, i5 -1>) ; CHECK-NEXT: [[M:%.*]] = zext <3 x i5> [[TMP1]] to <3 x i8> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %e = zext <3 x i5> %x to <3 x i8> %m = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %e, <3 x i8> <i8 7, i8 15, i8 31>) ret <3 x i8> %m } ; simplifies define i8 @umax_zext_constant_big(i5 %x) { ; CHECK-LABEL: @umax_zext_constant_big( ; CHECK-NEXT: ret i8 126 ; %e = zext i5 %x to i8 %m = call i8 @llvm.umax.i8(i8 %e, i8 126) ret i8 %m } define i8 @umin_sext_constant(i5 %x) { ; CHECK-LABEL: @umin_sext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umin.i5(i5 [[X:%.*]], i5 7) ; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %e = sext i5 %x to i8 %m = call i8 @llvm.umin.i8(i8 %e, i8 7) ret i8 %m } ; negative test define i8 @umin_sext_constant_big(i5 %x) { ; CHECK-LABEL: @umin_sext_constant_big( ; CHECK-NEXT: [[E:%.*]] = sext i5 [[X:%.*]] to i8 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[E]], i8 126) ; CHECK-NEXT: ret i8 [[M]] ; %e = sext i5 %x to i8 %m = call i8 @llvm.umin.i8(i8 %e, i8 126) ret i8 %m } define i8 @umin_zext_constant(i5 %x) { ; CHECK-LABEL: @umin_zext_constant( ; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umin.i5(i5 [[X:%.*]], i5 7) ; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[M]] ; %e = zext i5 %x to i8 %m = call i8 @llvm.umin.i8(i8 %e, i8 7) ret i8 %m } ; simplifies define i8 @umin_zext_constant_big(i5 %x) { ; CHECK-LABEL: @umin_zext_constant_big( ; CHECK-NEXT: [[E:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: ret i8 [[E]] ; %e = zext i5 %x to i8 %m = call i8 @llvm.umin.i8(i8 %e, i8 126) ret i8 %m } ; negative test define i8 @umin_zext_constant_uses(i5 %x) { ; CHECK-LABEL: @umin_zext_constant_uses( ; CHECK-NEXT: [[E:%.*]] = zext i5 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[E]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[E]], i8 7) ; CHECK-NEXT: ret i8 [[M]] ; %e = zext i5 %x to i8 call void @use(i8 %e) %m = call i8 @llvm.umin.i8(i8 %e, i8 7) ret i8 %m } define i8 @smax_of_nots(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_of_nots( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %noty = xor i8 %y, -1 %m = call i8 @llvm.smax.i8(i8 %notx, i8 %noty) ret i8 %m } ; Vectors are ok (including undef lanes of not ops) define <3 x i8> @smin_of_nots(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smin_of_nots( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = xor <3 x i8> [[TMP1]], <i8 -1, i8 -1, i8 -1> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %notx = xor <3 x i8> %x, <i8 -1, i8 undef, i8 -1> %noty = xor <3 x i8> %y, <i8 -1, i8 -1, i8 undef> %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %notx, <3 x i8> %noty) ret <3 x i8> %m } ; An extra use is ok. define i8 @umax_of_nots(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_of_nots( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 [[X]]) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %noty = xor i8 %y, -1 %m = call i8 @llvm.umax.i8(i8 %notx, i8 %noty) ret i8 %m } ; An extra use is ok. define i8 @umin_of_nots(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_of_nots( ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y]]) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %noty = xor i8 %y, -1 call void @use(i8 %noty) %m = call i8 @llvm.umin.i8(i8 %notx, i8 %noty) ret i8 %m } ; Negative test - too many uses define i8 @umin_of_nots_uses(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_of_nots_uses( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NOTX]], i8 [[NOTY]]) ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %noty = xor i8 %y, -1 call void @use(i8 %noty) %m = call i8 @llvm.umin.i8(i8 %notx, i8 %noty) ret i8 %m } ; Canonicalize 'not' after min/max. define i8 @smax_of_not_and_const(i8 %x) { ; CHECK-LABEL: @smax_of_not_and_const( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 -43) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %m = call i8 @llvm.smax.i8(i8 %notx, i8 42) ret i8 %m } ; Vectors are ok (including undef lanes of not ops and min/max constant operand) define <3 x i8> @smin_of_not_and_const(<3 x i8> %x) { ; CHECK-LABEL: @smin_of_not_and_const( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 -43, i8 undef, i8 -44>) ; CHECK-NEXT: [[M:%.*]] = xor <3 x i8> [[TMP1]], <i8 -1, i8 -1, i8 -1> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %notx = xor <3 x i8> %x, <i8 -1, i8 -1, i8 undef> %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> <i8 42, i8 undef, i8 43>, <3 x i8> %notx) ret <3 x i8> %m } define i8 @umax_of_not_and_const(i8 %x) { ; CHECK-LABEL: @umax_of_not_and_const( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 -45) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %m = call i8 @llvm.umax.i8(i8 %notx, i8 44) ret i8 %m } define i8 @umin_of_not_and_const(i8 %x) { ; CHECK-LABEL: @umin_of_not_and_const( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 44) ; CHECK-NEXT: [[M:%.*]] = xor i8 [[TMP1]], -1 ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %m = call i8 @llvm.umin.i8(i8 -45, i8 %notx) ret i8 %m } define i8 @umin_of_not_and_smax(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @umin_of_not_and_smax( ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[NOTZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTZ]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[Y]], i8 [[Z]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[M2:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: ret i8 [[M2]] ; %notx = xor i8 %x, -1 %noty = xor i8 %y, -1 call void @use(i8 %noty) %notz = xor i8 %z, -1 call void @use(i8 %notz) %m1 = call i8 @llvm.smax.i8(i8 %noty, i8 %notz) %m2 = call i8 @llvm.umin.i8(i8 %m1, i8 %notx) ret i8 %m2 } define i8 @smin_of_umax_and_not(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @smin_of_umax_and_not( ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[NOTZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTZ]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[Z]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[M2:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: ret i8 [[M2]] ; %notx = xor i8 %x, -1 %noty = xor i8 %y, -1 call void @use(i8 %noty) %notz = xor i8 %z, -1 call void @use(i8 %notz) %m1 = call i8 @llvm.umax.i8(i8 %noty, i8 %notz) %m2 = call i8 @llvm.smin.i8(i8 %notx, i8 %m1) ret i8 %m2 } ; Negative test - don't infinite loop on constant expression define i8 @umin_of_not_and_nontrivial_const(i8 %x) { ; CHECK-LABEL: @umin_of_not_and_nontrivial_const( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NOTX]], i8 ptrtoint (i8 (i8)* @umin_of_not_and_nontrivial_const to i8)) ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 %m = call i8 @llvm.umin.i8(i8 ptrtoint (i8(i8)* @umin_of_not_and_nontrivial_const to i8), i8 %notx) ret i8 %m } ; Negative test - too many uses define i8 @umin_of_not_and_const_uses(i8 %x) { ; CHECK-LABEL: @umin_of_not_and_const_uses( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NOTX]], i8 -45) ; CHECK-NEXT: ret i8 [[M]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %m = call i8 @llvm.umin.i8(i8 -45, i8 %notx) ret i8 %m } define i8 @not_smax_of_nots(i8 %x, i8 %y) { ; CHECK-LABEL: @not_smax_of_nots( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: ret i8 [[TMP1]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %noty = xor i8 %y, -1 call void @use(i8 %noty) %m = call i8 @llvm.smax.i8(i8 %notx, i8 %noty) %notm = xor i8 %m, -1 ret i8 %notm } define i8 @not_smin_of_nots(i8 %x, i8 %y) { ; CHECK-LABEL: @not_smin_of_nots( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTY]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NOTX]], i8 [[NOTY]]) ; CHECK-NEXT: call void @use(i8 [[M]]) ; CHECK-NEXT: [[NOTM:%.*]] = xor i8 [[M]], -1 ; CHECK-NEXT: ret i8 [[NOTM]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %noty = xor i8 %y, -1 call void @use(i8 %noty) %m = call i8 @llvm.smin.i8(i8 %notx, i8 %noty) call void @use(i8 %m) %notm = xor i8 %m, -1 ret i8 %notm } define i8 @not_umax_of_not(i8 %x, i8 %y) { ; CHECK-LABEL: @not_umax_of_not( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[TMP1]]) ; CHECK-NEXT: ret i8 [[TMP2]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %m = call i8 @llvm.umax.i8(i8 %notx, i8 %y) %notm = xor i8 %m, -1 ret i8 %notm } ; Negative test - this would require an extra instruction. define i8 @not_umin_of_not(i8 %x, i8 %y) { ; CHECK-LABEL: @not_umin_of_not( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NOTX]], i8 [[Y:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M]]) ; CHECK-NEXT: [[NOTM:%.*]] = xor i8 [[M]], -1 ; CHECK-NEXT: ret i8 [[NOTM]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %m = call i8 @llvm.umin.i8(i8 %notx, i8 %y) call void @use(i8 %m) %notm = xor i8 %m, -1 ret i8 %notm } define i8 @not_umin_of_not_constant_op(i8 %x) { ; CHECK-LABEL: @not_umin_of_not_constant_op( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 -43) ; CHECK-NEXT: ret i8 [[TMP1]] ; %notx = xor i8 %x, -1 call void @use(i8 %notx) %m = call i8 @llvm.umin.i8(i8 %notx, i8 42) %notm = xor i8 %m, -1 ret i8 %notm } define i8 @smax_negation(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_negation( ; CHECK-NEXT: [[S1:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false) ; CHECK-NEXT: ret i8 [[TMP1]] ; %s1 = sub i8 %x, %y %s2 = sub i8 %y, %x %r = call i8 @llvm.smax.i8(i8 %s1, i8 %s2) ret i8 %r } define i8 @smax_negation_nsw(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_negation_nsw( ; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 true) ; CHECK-NEXT: ret i8 [[TMP1]] ; %s1 = sub nsw i8 %x, %y %s2 = sub nsw i8 %y, %x %r = call i8 @llvm.smax.i8(i8 %s1, i8 %s2) ret i8 %r } define i8 @smax_negation_not_nsw(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_negation_not_nsw( ; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false) ; CHECK-NEXT: ret i8 [[TMP1]] ; %s1 = sub nsw i8 %x, %y %s2 = sub nuw i8 %y, %x %r = call i8 @llvm.smax.i8(i8 %s1, i8 %s2) ret i8 %r } define <3 x i8> @smax_negation_vec(<3 x i8> %x) { ; CHECK-LABEL: @smax_negation_vec( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.abs.v3i8(<3 x i8> [[X:%.*]], i1 false) ; CHECK-NEXT: ret <3 x i8> [[TMP1]] ; %s = sub <3 x i8> <i8 0, i8 undef, i8 0>, %x %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %x, <3 x i8> %s) ret <3 x i8> %r } define i8 @smin_negation(i8 %x, i8 %y) { ; CHECK-LABEL: @smin_negation( ; CHECK-NEXT: [[S1:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false) ; CHECK-NEXT: [[NABS:%.*]] = sub i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[NABS]] ; %s1 = sub i8 %x, %y %s2 = sub i8 %y, %x %r = call i8 @llvm.smin.i8(i8 %s1, i8 %s2) ret i8 %r } define i8 @umax_negation(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_negation( ; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 true) ; CHECK-NEXT: [[NABS:%.*]] = sub nsw i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[NABS]] ; %s1 = sub nsw i8 %x, %y %s2 = sub nsw i8 %y, %x %r = call i8 @llvm.umax.i8(i8 %s1, i8 %s2) ret i8 %r } define i8 @umin_negation(i8 %x) { ; CHECK-LABEL: @umin_negation( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 true) ; CHECK-NEXT: ret i8 [[TMP1]] ; %s = sub nsw i8 0, %x %r = call i8 @llvm.umin.i8(i8 %s, i8 %x) ret i8 %r } define i8 @smax_negation_uses(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_negation_uses( ; CHECK-NEXT: [[S2:%.*]] = sub i8 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: call void @use(i8 [[S2]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S2]], i1 false) ; CHECK-NEXT: ret i8 [[TMP1]] ; %s1 = sub i8 %x, %y %s2 = sub i8 %y, %x call void @use(i8 %s2) %r = call i8 @llvm.smax.i8(i8 %s1, i8 %s2) ret i8 %r } define i8 @clamp_two_vals_smax_smin(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_smax_smin( ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], 43 ; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i8 42, i8 43 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.smax.i8(i8 %x, i8 42) %r = call i8 @llvm.smin.i8(i8 %m, i8 43) ret i8 %r } define <3 x i8> @clamp_two_vals_smin_smax(<3 x i8> %x) { ; CHECK-LABEL: @clamp_two_vals_smin_smax( ; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt <3 x i8> [[X:%.*]], <i8 41, i8 41, i8 41> ; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i8> <i8 42, i8 42, i8 42>, <3 x i8> <i8 41, i8 41, i8 41> ; CHECK-NEXT: ret <3 x i8> [[R]] ; %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 42, i8 42>) %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %m, <3 x i8> <i8 41, i8 41, i8 41>) ret <3 x i8> %r } define i8 @clamp_two_vals_umax_umin(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_umax_umin( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[X:%.*]], 43 ; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i8 42, i8 43 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umax.i8(i8 %x, i8 42) %r = call i8 @llvm.umin.i8(i8 %m, i8 43) ret i8 %r } define i8 @clamp_two_vals_umin_umax(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_umin_umax( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], 41 ; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i8 42, i8 41 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umin.i8(i8 %x, i8 42) %r = call i8 @llvm.umax.i8(i8 %m, i8 41) ret i8 %r } ; Negative test - mismatched signs define i8 @clamp_two_vals_smax_umin(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_smax_umin( ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 42) ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[M]], i8 43) ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.smax.i8(i8 %x, i8 42) %r = call i8 @llvm.umin.i8(i8 %m, i8 43) ret i8 %r } ; Negative test - wrong range define i8 @clamp_three_vals_smax_smin(i8 %x) { ; CHECK-LABEL: @clamp_three_vals_smax_smin( ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 42) ; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[M]], i8 44) ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.smax.i8(i8 %x, i8 42) %r = call i8 @llvm.smin.i8(i8 %m, i8 44) ret i8 %r } ; Edge cases are simplified define i8 @clamp_two_vals_umax_umin_edge(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_umax_umin_edge( ; CHECK-NEXT: ret i8 0 ; %m = call i8 @llvm.umax.i8(i8 %x, i8 255) %r = call i8 @llvm.umin.i8(i8 %m, i8 0) ret i8 %r } ; Edge cases are simplified define i8 @clamp_two_vals_umin_umax_edge(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_umin_umax_edge( ; CHECK-NEXT: ret i8 -1 ; %m = call i8 @llvm.umin.i8(i8 %x, i8 0) %r = call i8 @llvm.umax.i8(i8 %m, i8 255) ret i8 %r } ; Edge cases are simplified define i8 @clamp_two_vals_smax_smin_edge(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_smax_smin_edge( ; CHECK-NEXT: ret i8 -128 ; %m = call i8 @llvm.smax.i8(i8 %x, i8 127) %r = call i8 @llvm.smin.i8(i8 %m, i8 128) ret i8 %r } ; Edge cases are simplified define i8 @clamp_two_vals_smin_smax_edge(i8 %x) { ; CHECK-LABEL: @clamp_two_vals_smin_smax_edge( ; CHECK-NEXT: ret i8 127 ; %m = call i8 @llvm.smin.i8(i8 %x, i8 128) %r = call i8 @llvm.smax.i8(i8 %m, i8 127) ret i8 %r } define i8 @umin_non_zero_idiom1(i8 %a) { ; CHECK-LABEL: @umin_non_zero_idiom1( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0 ; CHECK-NEXT: [[RES:%.*]] = zext i1 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[RES]] ; %res = call i8 @llvm.umin.i8(i8 %a, i8 1) ret i8 %res } define i8 @umin_non_zero_idiom2(i8 %a) { ; CHECK-LABEL: @umin_non_zero_idiom2( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0 ; CHECK-NEXT: [[RES:%.*]] = zext i1 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[RES]] ; %res = call i8 @llvm.umin.i8(i8 1, i8 %a) ret i8 %res } define <3 x i8> @umin_non_zero_idiom3(<3 x i8> %a) { ; CHECK-LABEL: @umin_non_zero_idiom3( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <3 x i8> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[RES:%.*]] = zext <3 x i1> [[TMP1]] to <3 x i8> ; CHECK-NEXT: ret <3 x i8> [[RES]] ; %res = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> <i8 1, i8 1, i8 1>) ret <3 x i8> %res } define <3 x i8> @umin_non_zero_idiom4(<3 x i8> %a) { ; CHECK-LABEL: @umin_non_zero_idiom4( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <3 x i8> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[RES:%.*]] = zext <3 x i1> [[TMP1]] to <3 x i8> ; CHECK-NEXT: ret <3 x i8> [[RES]] ; %res = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> <i8 1, i8 undef, i8 undef>) ret <3 x i8> %res } define i1 @umin_eq_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @umin_eq_zero( ; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[A:%.*]], i8 [[B:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[UMIN]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %umin = call i8 @llvm.umin.i8(i8 %a, i8 %b) %res = icmp eq i8 %umin, 0 ret i1 %res } define <3 x i1> @umin_eq_zero2(<3 x i8> %a, <3 x i8> %b) { ; CHECK-LABEL: @umin_eq_zero2( ; CHECK-NEXT: [[UMIN:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[A:%.*]], <3 x i8> [[B:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = icmp eq <3 x i8> [[UMIN]], zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[RES]] ; %umin = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> %b) %res = icmp eq <3 x i8> %umin, zeroinitializer ret <3 x i1> %res } define i1 @umin_ne_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @umin_ne_zero( ; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[A:%.*]], i8 [[B:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = icmp ne i8 [[UMIN]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %umin = call i8 @llvm.umin.i8(i8 %a, i8 %b) %res = icmp ne i8 %umin, 0 ret i1 %res } define <3 x i1> @umin_ne_zero2(<3 x i8> %a, <3 x i8> %b) { ; CHECK-LABEL: @umin_ne_zero2( ; CHECK-NEXT: [[UMIN:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[A:%.*]], <3 x i8> [[B:%.*]]) ; CHECK-NEXT: [[RES:%.*]] = icmp ne <3 x i8> [[UMIN]], zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[RES]] ; %umin = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> %b) %res = icmp ne <3 x i8> %umin, zeroinitializer ret <3 x i1> %res } define i8 @smax(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @smax( ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Z:%.*]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smax.i8(i8 [[M2]], i8 [[Y:%.*]]) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 %y) %m2 = call i8 @llvm.smax.i8(i8 %x, i8 %z) %m3 = call i8 @llvm.smax.i8(i8 %m1, i8 %m2) ret i8 %m3 } define <3 x i8> @smin(<3 x i8> %x, <3 x i8> %y, <3 x i8> %z) { ; CHECK-LABEL: @smin( ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Z:%.*]]) ; CHECK-NEXT: [[M3:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[M2]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: ret <3 x i8> [[M3]] ; %m1 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %y, <3 x i8> %x) %m2 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %x, <3 x i8> %z) %m3 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %m1, <3 x i8> %m2) ret <3 x i8> %m3 } define i8 @umax(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @umax( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.umax.i8(i8 [[M1]], i8 [[Z:%.*]]) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.umax.i8(i8 %x, i8 %y) call void @use(i8 %m1) %m2 = call i8 @llvm.umax.i8(i8 %z, i8 %x) %m3 = call i8 @llvm.umax.i8(i8 %m1, i8 %m2) ret i8 %m3 } define i8 @umin(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @umin( ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[Z:%.*]], i8 [[X:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.umin.i8(i8 [[M2]], i8 [[Y:%.*]]) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.umin.i8(i8 %y, i8 %x) %m2 = call i8 @llvm.umin.i8(i8 %z, i8 %x) call void @use(i8 %m2) %m3 = call i8 @llvm.umin.i8(i8 %m1, i8 %m2) ret i8 %m3 } ; negative test - too many uses define i8 @smax_uses(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @smax_uses( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Z:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 [[M2]]) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 %y) call void @use(i8 %m1) %m2 = call i8 @llvm.smax.i8(i8 %x, i8 %z) call void @use(i8 %m2) %m3 = call i8 @llvm.smax.i8(i8 %m1, i8 %m2) ret i8 %m3 } ; negative test - must have common operand define i8 @smax_no_common_op(i8 %x, i8 %y, i8 %z, i8 %w) { ; CHECK-LABEL: @smax_no_common_op( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[W:%.*]], i8 [[Z:%.*]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 [[M2]]) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 %y) %m2 = call i8 @llvm.smax.i8(i8 %w, i8 %z) %m3 = call i8 @llvm.smax.i8(i8 %m1, i8 %m2) ret i8 %m3 } define i8 @umax_demand_lshr(i8 %x) { ; CHECK-LABEL: @umax_demand_lshr( ; CHECK-NEXT: [[R:%.*]] = lshr i8 [[X:%.*]], 4 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umax.i8(i8 %x, i8 15) %r = lshr i8 %m, 4 ret i8 %r } define i8 @umax_demand_and(i8 %x) { ; CHECK-LABEL: @umax_demand_and( ; CHECK-NEXT: [[R:%.*]] = and i8 [[X:%.*]], 10 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umax.i8(i8 1, i8 %x) %r = and i8 %m, 10 ret i8 %r } define i8 @umin_demand_or_31_30(i8 %x) { ; CHECK-LABEL: @umin_demand_or_31_30( ; CHECK-NEXT: [[R:%.*]] = or i8 [[X:%.*]], 31 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umin.i8(i8 -30, i8 %x) %r = or i8 %m, 31 ret i8 %r } define i8 @umin_demand_and_7_8(i8 %x) { ; CHECK-LABEL: @umin_demand_and_7_8( ; CHECK-NEXT: [[R:%.*]] = and i8 [[X:%.*]], -8 ; CHECK-NEXT: ret i8 [[R]] ; %m = call i8 @llvm.umin.i8(i8 %x, i8 -7) %r = and i8 %m, -8 ret i8 %r } define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_nsw_smax( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub nsw i8 0, %x %ny = sub nsw i8 0, %y %m = call i8 @llvm.smax.i8(i8 %nx, i8 %ny) ret i8 %m } define <3 x i8> @neg_neg_nsw_smin(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @neg_neg_nsw_smin( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sub nsw <3 x i8> zeroinitializer, [[TMP1]] ; CHECK-NEXT: ret <3 x i8> [[M]] ; %nx = sub nsw <3 x i8> zeroinitializer, %x %ny = sub nsw <3 x i8> zeroinitializer, %y %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %nx, <3 x i8> %ny) ret <3 x i8> %m } define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_nsw_smax_use0( ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]] ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub nsw i8 0, %x call void @use(i8 %nx) %ny = sub nsw i8 0, %y %m = call i8 @llvm.smax.i8(i8 %nx, i8 %ny) ret i8 %m } define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_nsw_smin_use1( ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]] ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y]]) ; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub nsw i8 0, %x %ny = sub nsw i8 0, %y call void @use(i8 %ny) %m = call i8 @llvm.smin.i8(i8 %nx, i8 %ny) ret i8 %m } ; negative test - too many uses define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_nsw_smin_use2( ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]] ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]] ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub nsw i8 0, %x call void @use(i8 %nx) %ny = sub nsw i8 0, %y call void @use(i8 %ny) %m = call i8 @llvm.smin.i8(i8 %nx, i8 %ny) ret i8 %m } ; negative test - need nsw on both ops define i8 @neg_neg_smax(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_smax( ; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]] ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]] ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub i8 0, %x %ny = sub nsw i8 0, %y %m = call i8 @llvm.smax.i8(i8 %nx, i8 %ny) ret i8 %m } ; negative test - need nsw on both ops define i8 @neg_neg_smin(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_smin( ; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]] ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]] ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub i8 0, %x %ny = sub nsw i8 0, %y %m = call i8 @llvm.smin.i8(i8 %nx, i8 %ny) ret i8 %m } ; negative test - need signed min/max define i8 @neg_neg_nsw_umin(i8 %x, i8 %y) { ; CHECK-LABEL: @neg_neg_nsw_umin( ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]] ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]] ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: ret i8 [[M]] ; %nx = sub nsw i8 0, %x %ny = sub nsw i8 0, %y %m = call i8 @llvm.umin.i8(i8 %nx, i8 %ny) ret i8 %m } define i8 @freeToInvertSub(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvertSub( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[TMP1]], [[Z]] ; CHECK-NEXT: ret i8 [[SUB]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) %sub = sub i8 %nz, %m ret i8 %sub } define i8 @freeToInvertSub_uses(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvertSub_uses( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[M]]) ; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[NZ]], [[M]] ; CHECK-NEXT: ret i8 [[SUB]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) call void @use(i8 %m) %sub = sub i8 %nz, %m ret i8 %sub } define i8 @freeToInvert(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvert( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[Z]]) ; CHECK-NEXT: ret i8 [[TMP2]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) %m2 = call i8 @llvm.smin.i8(i8 %m1, i8 %nz) %not = xor i8 %m2, -1 ret i8 %not } define i8 @freeToInvert_use1(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvert_use1( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[M1]], -1 ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[TMP1]]) ; CHECK-NEXT: ret i8 [[TMP2]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) call void @use(i8 %m1) %m2 = call i8 @llvm.smin.i8(i8 %m1, i8 %nz) %not = xor i8 %m2, -1 ret i8 %not } define i8 @freeToInvert_use2(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvert_use2( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M2]], -1 ; CHECK-NEXT: ret i8 [[NOT]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) %m2 = call i8 @llvm.smin.i8(i8 %m1, i8 %nz) call void @use(i8 %m2) %not = xor i8 %m2, -1 ret i8 %not } define i8 @freeToInvert_use3(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @freeToInvert_use3( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M2]], -1 ; CHECK-NEXT: ret i8 [[NOT]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) call void @use(i8 %m1) %m2 = call i8 @llvm.smin.i8(i8 %m1, i8 %nz) call void @use(i8 %m2) %not = xor i8 %m2, -1 ret i8 %not } define i8 @freeToInvert_two_minmax_ops(i8 %x, i8 %y, i8 %z, i8 %w) { ; CHECK-LABEL: @freeToInvert_two_minmax_ops( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: [[NW:%.*]] = xor i8 [[W:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[NW]]) ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smin.i8(i8 [[W]], i8 [[Z]]) ; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[TMP2]]) ; CHECK-NEXT: ret i8 [[TMP3]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 %nw = xor i8 %w, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) call void @use(i8 %nw) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) %m2 = call i8 @llvm.smax.i8(i8 %nw, i8 %nz) %m3 = call i8 @llvm.smin.i8(i8 %m1, i8 %m2) %not = xor i8 %m3, -1 ret i8 %not } define i8 @freeToInvert_two_minmax_ops_use1(i8 %x, i8 %y, i8 %z, i8 %w) { ; CHECK-LABEL: @freeToInvert_two_minmax_ops_use1( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: [[NW:%.*]] = xor i8 [[W:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[NW]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[NW]], i8 [[NZ]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[M2]]) ; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M3]], -1 ; CHECK-NEXT: ret i8 [[NOT]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 %nw = xor i8 %w, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) call void @use(i8 %nw) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) call void @use(i8 %m1) %m2 = call i8 @llvm.smax.i8(i8 %nw, i8 %nz) %m3 = call i8 @llvm.smin.i8(i8 %m1, i8 %m2) %not = xor i8 %m3, -1 ret i8 %not } define i8 @freeToInvert_two_minmax_ops_use2(i8 %x, i8 %y, i8 %z, i8 %w) { ; CHECK-LABEL: @freeToInvert_two_minmax_ops_use2( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: [[NW:%.*]] = xor i8 [[W:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[NW]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[NW]], i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[M2]]) ; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M3]], -1 ; CHECK-NEXT: ret i8 [[NOT]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 %nw = xor i8 %w, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) call void @use(i8 %nw) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) %m2 = call i8 @llvm.smax.i8(i8 %nw, i8 %nz) call void @use(i8 %m2) %m3 = call i8 @llvm.smin.i8(i8 %m1, i8 %m2) %not = xor i8 %m3, -1 ret i8 %not } define i8 @freeToInvert_two_minmax_ops_use3(i8 %x, i8 %y, i8 %z, i8 %w) { ; CHECK-LABEL: @freeToInvert_two_minmax_ops_use3( ; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1 ; CHECK-NEXT: [[NW:%.*]] = xor i8 [[W:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NX]]) ; CHECK-NEXT: call void @use(i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[NW]]) ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[NW]], i8 [[NZ]]) ; CHECK-NEXT: call void @use(i8 [[M2]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[M2]]) ; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M3]], -1 ; CHECK-NEXT: ret i8 [[NOT]] ; %nx = xor i8 %x, -1 %ny = xor i8 %y, -1 %nz = xor i8 %z, -1 %nw = xor i8 %w, -1 call void @use(i8 %nx) call void @use(i8 %ny) call void @use(i8 %nz) call void @use(i8 %nw) %m1 = call i8 @llvm.umax.i8(i8 %nx, i8 %ny) call void @use(i8 %m1) %m2 = call i8 @llvm.smax.i8(i8 %nw, i8 %nz) call void @use(i8 %m2) %m3 = call i8 @llvm.smin.i8(i8 %m1, i8 %m2) %not = xor i8 %m3, -1 ret i8 %not } define i8 @sub_not_min_max(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @sub_not_min_max( ; CHECK-NEXT: [[NOTR:%.*]] = xor i8 [[R:%.*]], -1 ; CHECK-NEXT: [[NOTG:%.*]] = xor i8 [[G:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTG]]) ; CHECK-NEXT: [[NOTB:%.*]] = xor i8 [[B:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTB]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NOTR]], i8 [[NOTG]]) ; CHECK-NEXT: [[K:%.*]] = call i8 @llvm.smin.i8(i8 [[M]], i8 [[NOTB]]) ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[NOTR]], [[K]] ; CHECK-NEXT: ret i8 [[CK]] ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 call void @use(i8 %notg) %notb = xor i8 %b, -1 call void @use(i8 %notb) %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k ret i8 %ck } define i8 @sub_not_min_max_uses1(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @sub_not_min_max_uses1( ; CHECK-NEXT: [[NOTR:%.*]] = xor i8 [[R:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTR]]) ; CHECK-NEXT: [[NOTG:%.*]] = xor i8 [[G:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTG]]) ; CHECK-NEXT: [[NOTB:%.*]] = xor i8 [[B:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTB]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NOTR]], i8 [[NOTG]]) ; CHECK-NEXT: [[K:%.*]] = call i8 @llvm.smin.i8(i8 [[M]], i8 [[NOTB]]) ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[NOTR]], [[K]] ; CHECK-NEXT: ret i8 [[CK]] ; %notr = xor i8 %r, -1 call void @use(i8 %notr) %notg = xor i8 %g, -1 call void @use(i8 %notg) %notb = xor i8 %b, -1 call void @use(i8 %notb) %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k ret i8 %ck } define i8 @sub_not_min_max_uses2(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @sub_not_min_max_uses2( ; CHECK-NEXT: [[NOTR:%.*]] = xor i8 [[R:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTR]]) ; CHECK-NEXT: [[NOTG:%.*]] = xor i8 [[G:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTG]]) ; CHECK-NEXT: [[NOTB:%.*]] = xor i8 [[B:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTB]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NOTR]], i8 [[NOTG]]) ; CHECK-NEXT: call void @use(i8 [[M]]) ; CHECK-NEXT: [[K:%.*]] = call i8 @llvm.smin.i8(i8 [[M]], i8 [[NOTB]]) ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[NOTR]], [[K]] ; CHECK-NEXT: ret i8 [[CK]] ; %notr = xor i8 %r, -1 call void @use(i8 %notr) %notg = xor i8 %g, -1 call void @use(i8 %notg) %notb = xor i8 %b, -1 call void @use(i8 %notb) %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) call void @use(i8 %m) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k ret i8 %ck } declare void @use4(i8, i8, i8, i8) define void @cmyk(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[R:%.*]], i8 [[G:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k %mk = sub i8 %notg, %k %yk = sub i8 %notb, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as above, but flip the operands of %k. define void @cmyk_commute1(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute1( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[R:%.*]], i8 [[G:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %notb, i8 %m) %ck = sub i8 %notr, %k %mk = sub i8 %notg, %k %yk = sub i8 %notb, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as above, but also flip the operands of %m. define void @cmyk_commute2(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute2( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %notb, i8 %m) %ck = sub i8 %notr, %k %mk = sub i8 %notg, %k %yk = sub i8 %notb, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as original, but only flip the operands of %m. define void @cmyk_commute3(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute3( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k %mk = sub i8 %notg, %k %yk = sub i8 %notb, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Not exactly a commute, but make sure order of folds doesn't change anything. ; Also verify that we don't need matching min/max ops. define void @cmyk_commute4(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute4( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.umin.i8(i8 %m, i8 %notb) %yk = sub i8 %notb, %k %ck = sub i8 %notr, %k %mk = sub i8 %notg, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Not exactly a commute, but make sure order of folds doesn't change anything. ; Also verify that we don't need matching min/max ops. define void @cmyk_commute5(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute5( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smax.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k %yk = sub i8 %notb, %k %mk = sub i8 %notg, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } define void @cmyk_commute6(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute6( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[R:%.*]], i8 [[G:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[R]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[G]], [[TMP2]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[B]], [[TMP2]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %k, %notr %mk = sub i8 %k, %notg %yk = sub i8 %k, %notb call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as above, but flip the operands of %k. define void @cmyk_commute7(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute7( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[R:%.*]], i8 [[G:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[R]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[G]], [[TMP2]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[B]], [[TMP2]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notr, i8 %notg) %k = call i8 @llvm.smin.i8(i8 %notb, i8 %m) %ck = sub i8 %k, %notr %mk = sub i8 %k, %notg %yk = sub i8 %k, %notb call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as above, but also flip the operands of %m. define void @cmyk_commute8(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute8( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[R]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[G]], [[TMP2]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[B]], [[TMP2]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %notb, i8 %m) %ck = sub i8 %k, %notr %mk = sub i8 %k, %notg %yk = sub i8 %k, %notb call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Same as original, but only flip the operands of %m. define void @cmyk_commute9(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute9( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[R]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[G]], [[TMP2]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[B]], [[TMP2]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %k, %notr %mk = sub i8 %k, %notg %yk = sub i8 %k, %notb call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Not exactly a commute, but make sure order of folds doesn't change anything. ; Also verify that we don't need matching min/max ops. define void @cmyk_commute10(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute10( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[TMP2]], [[B]] ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[R]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[TMP2]], [[G]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smin.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.umin.i8(i8 %m, i8 %notb) %yk = sub i8 %notb, %k %ck = sub i8 %k, %notr %mk = sub i8 %notg, %k call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } ; Not exactly a commute, but make sure order of folds doesn't change anything. ; Also verify that we don't need matching min/max ops. define void @cmyk_commute11(i8 %r, i8 %g, i8 %b) { ; CHECK-LABEL: @cmyk_commute11( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[G:%.*]], i8 [[R:%.*]]) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[B:%.*]], i8 [[TMP1]]) ; CHECK-NEXT: [[K:%.*]] = xor i8 [[TMP2]], -1 ; CHECK-NEXT: [[CK:%.*]] = sub i8 [[TMP2]], [[R]] ; CHECK-NEXT: [[YK:%.*]] = sub i8 [[B]], [[TMP2]] ; CHECK-NEXT: [[MK:%.*]] = sub i8 [[G]], [[TMP2]] ; CHECK-NEXT: call void @use4(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]]) ; CHECK-NEXT: ret void ; %notr = xor i8 %r, -1 %notg = xor i8 %g, -1 %notb = xor i8 %b, -1 %m = call i8 @llvm.smax.i8(i8 %notg, i8 %notr) %k = call i8 @llvm.smin.i8(i8 %m, i8 %notb) %ck = sub i8 %notr, %k %yk = sub i8 %k, %notb %mk = sub i8 %k, %notg call void @use4(i8 %ck, i8 %mk, i8 %yk, i8 %k) ret void } define i8 @smax_offset(i8 %x) { ; CHECK-LABEL: @smax_offset( ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 -127) ; CHECK-NEXT: [[M:%.*]] = add nsw i8 [[TMP1]], 3 ; CHECK-NEXT: ret i8 [[M]] ; %a = add nsw i8 %x, 3 %m = call i8 @llvm.smax.i8(i8 %a, i8 -124) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @smax_offset_limit(i8 %x) { ; CHECK-LABEL: @smax_offset_limit( ; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 3 ; CHECK-NEXT: ret i8 [[A]] ; %a = add nsw i8 %x, 3 %m = call i8 @llvm.smax.i8(i8 %a, i8 -125) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @smax_offset_overflow(i8 %x) { ; CHECK-LABEL: @smax_offset_overflow( ; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 3 ; CHECK-NEXT: ret i8 [[A]] ; %a = add nsw i8 %x, 3 %m = call i8 @llvm.smax.i8(i8 %a, i8 -126) ret i8 %m } ; negative test - require nsw define i8 @smax_offset_may_wrap(i8 %x) { ; CHECK-LABEL: @smax_offset_may_wrap( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 3 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[A]], i8 -124) ; CHECK-NEXT: ret i8 [[M]] ; %a = add i8 %x, 3 %m = call i8 @llvm.smax.i8(i8 %a, i8 -124) ret i8 %m } ; negative test define i8 @smax_offset_uses(i8 %x) { ; CHECK-LABEL: @smax_offset_uses( ; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 3 ; CHECK-NEXT: call void @use(i8 [[A]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[A]], i8 -124) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nsw i8 %x, 3 call void @use(i8 %a) %m = call i8 @llvm.smax.i8(i8 %a, i8 -124) ret i8 %m } define <3 x i8> @smin_offset(<3 x i8> %x) { ; CHECK-LABEL: @smin_offset( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 -127, i8 -127, i8 -127>) ; CHECK-NEXT: [[M:%.*]] = or <3 x i8> [[TMP1]], <i8 124, i8 124, i8 124> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %a = add nsw nuw <3 x i8> %x, <i8 124, i8 124, i8 124> %m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %a, <3 x i8> <i8 -3, i8 -3, i8 -3>) ret <3 x i8> %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @smin_offset_limit(i8 %x) { ; CHECK-LABEL: @smin_offset_limit( ; CHECK-NEXT: ret i8 -3 ; %a = add nsw i8 %x, 125 %m = call i8 @llvm.smin.i8(i8 %a, i8 -3) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @smin_offset_overflow(i8 %x) { ; CHECK-LABEL: @smin_offset_overflow( ; CHECK-NEXT: ret i8 -3 ; %a = add nsw i8 %x, 126 %m = call i8 @llvm.smin.i8(i8 %a, i8 -3) ret i8 %m } ; negative test - require nsw define i8 @smin_offset_may_wrap(i8 %x) { ; CHECK-LABEL: @smin_offset_may_wrap( ; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], 124 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[A]], i8 -3) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nuw i8 %x, 124 %m = call i8 @llvm.smin.i8(i8 %a, i8 -3) ret i8 %m } ; negative test define i8 @smin_offset_uses(i8 %x) { ; CHECK-LABEL: @smin_offset_uses( ; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], 124 ; CHECK-NEXT: call void @use(i8 [[A]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[A]], i8 -3) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nsw i8 %x, 124 call void @use(i8 %a) %m = call i8 @llvm.smin.i8(i8 %a, i8 -3) ret i8 %m } ; Note: 'nsw' must not propagate here. define <3 x i8> @umax_offset(<3 x i8> %x) { ; CHECK-LABEL: @umax_offset( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 3, i8 3, i8 3>) ; CHECK-NEXT: [[M:%.*]] = add nuw <3 x i8> [[TMP1]], <i8 127, i8 127, i8 127> ; CHECK-NEXT: ret <3 x i8> [[M]] ; %a = add nsw nuw <3 x i8> %x, <i8 127, i8 127, i8 127> %m = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %a, <3 x i8> <i8 130, i8 130, i8 130>) ret <3 x i8> %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @umax_offset_limit(i8 %x) { ; CHECK-LABEL: @umax_offset_limit( ; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], 3 ; CHECK-NEXT: ret i8 [[A]] ; %a = add nuw i8 %x, 3 %m = call i8 @llvm.umax.i8(i8 %a, i8 3) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @umax_offset_overflow(i8 %x) { ; CHECK-LABEL: @umax_offset_overflow( ; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], 3 ; CHECK-NEXT: ret i8 [[A]] ; %a = add nuw i8 %x, 3 %m = call i8 @llvm.umax.i8(i8 %a, i8 2) ret i8 %m } ; negative test - require nuw define i8 @umax_offset_may_wrap(i8 %x) { ; CHECK-LABEL: @umax_offset_may_wrap( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 3 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[A]], i8 4) ; CHECK-NEXT: ret i8 [[M]] ; %a = add i8 %x, 3 %m = call i8 @llvm.umax.i8(i8 %a, i8 4) ret i8 %m } ; negative test define i8 @umax_offset_uses(i8 %x) { ; CHECK-LABEL: @umax_offset_uses( ; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], 3 ; CHECK-NEXT: call void @use(i8 [[A]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[A]], i8 4) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nuw i8 %x, 3 call void @use(i8 %a) %m = call i8 @llvm.umax.i8(i8 %a, i8 4) ret i8 %m } define i8 @umin_offset(i8 %x) { ; CHECK-LABEL: @umin_offset( ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i8 [[X:%.*]], 0 ; CHECK-NEXT: [[M:%.*]] = select i1 [[DOTNOT]], i8 -5, i8 -4 ; CHECK-NEXT: ret i8 [[M]] ; %a = add nuw i8 %x, 251 %m = call i8 @llvm.umin.i8(i8 %a, i8 252) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @umin_offset_limit(i8 %x) { ; CHECK-LABEL: @umin_offset_limit( ; CHECK-NEXT: ret i8 -4 ; %a = add nuw i8 %x, 252 %m = call i8 @llvm.umin.i8(i8 %a, i8 252) ret i8 %m } ; This is handled by InstSimplify; testing here to confirm assert. define i8 @umin_offset_overflow(i8 %x) { ; CHECK-LABEL: @umin_offset_overflow( ; CHECK-NEXT: ret i8 -4 ; %a = add nuw i8 %x, 253 %m = call i8 @llvm.umin.i8(i8 %a, i8 252) ret i8 %m } ; negative test - require nuw define i8 @umin_offset_may_wrap(i8 %x) { ; CHECK-LABEL: @umin_offset_may_wrap( ; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X:%.*]], -5 ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[A]], i8 -4) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nsw i8 %x, 251 %m = call i8 @llvm.umin.i8(i8 %a, i8 252) ret i8 %m } ; negative test define i8 @umin_offset_uses(i8 %x) { ; CHECK-LABEL: @umin_offset_uses( ; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], -5 ; CHECK-NEXT: call void @use(i8 [[A]]) ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[A]], i8 -4) ; CHECK-NEXT: ret i8 [[M]] ; %a = add nuw i8 %x, 251 call void @use(i8 %a) %m = call i8 @llvm.umin.i8(i8 %a, i8 252) ret i8 %m } ; TODO: This could transform, but undef element must not propagate to the new add. define <3 x i8> @umax_vector_splat_undef(<3 x i8> %x) { ; CHECK-LABEL: @umax_vector_splat_undef( ; CHECK-NEXT: [[A:%.*]] = add nuw <3 x i8> [[X:%.*]], <i8 undef, i8 64, i8 64> ; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[A]], <3 x i8> <i8 13, i8 -126, i8 -126>) ; CHECK-NEXT: ret <3 x i8> [[R]] ; %a = add nuw <3 x i8> %x, <i8 undef, i8 64, i8 64> %r = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %a, <3 x i8> <i8 13, i8 130, i8 130>) ret <3 x i8> %r } ; Issue #52884 - this would assert because of a failure to simplify. define i8 @smax_offset_simplify(i8 %x) { ; CHECK-LABEL: @smax_offset_simplify( ; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i8 [[X:%.*]], 50 ; CHECK-NEXT: ret i8 [[TMP1]] ; %1 = add nuw nsw i8 50, %x %m = call i8 @llvm.smax.i8(i8 %1, i8 -124) ret i8 %m } define <3 x i8> @smax_smax_reassoc_constants(<3 x i8> %x) { ; CHECK-LABEL: @smax_smax_reassoc_constants( ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 43, i8 44>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>) %m2 = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %m1, <3 x i8> <i8 43, i8 -43, i8 0>) ret <3 x i8> %m2 } define i8 @smin_smin_reassoc_constants(i8 %x) { ; CHECK-LABEL: @smin_smin_reassoc_constants( ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 -3) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.smin.i8(i8 %x, i8 97) %m2 = call i8 @llvm.smin.i8(i8 -3, i8 %m1) ret i8 %m2 } define <3 x i8> @umax_umax_reassoc_constants(<3 x i8> %x) { ; CHECK-LABEL: @umax_umax_reassoc_constants( ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 -113, i8 poison>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>) %m2 = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %m1, <3 x i8> <i8 43, i8 143, i8 poison>) ret <3 x i8> %m2 } ; extra use is ok define i8 @umin_umin_reassoc_constants(i8 %x) { ; CHECK-LABEL: @umin_umin_reassoc_constants( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 -116) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umin.i8(i8 140, i8 %x) call void @use(i8 %m1) %m2 = call i8 @llvm.umin.i8(i8 %m1, i8 42) ret i8 %m2 } ; negative test - must have matching intrinsics define i8 @smin_smax_reassoc_constants(i8 %x) { ; CHECK-LABEL: @smin_smax_reassoc_constants( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 -3) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.smin.i8(i8 %x, i8 97) %m2 = call i8 @llvm.smax.i8(i8 %m1, i8 -3) ret i8 %m2 } define i8 @smax_smax_reassoc_constant(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_smax_reassoc_constant( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 %y) %m2 = call i8 @llvm.smax.i8(i8 %m1, i8 42) ret i8 %m2 } define <3 x i8> @smin_smin_reassoc_constant(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smin_smin_reassoc_constant( ; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %x, <3 x i8> %y) %m2 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %m1, <3 x i8> <i8 43, i8 -43, i8 0>) ret <3 x i8> %m2 } define i8 @umax_umax_reassoc_constant(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_umax_reassoc_constant( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umax.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umax.i8(i8 %x, i8 %y) %m2 = call i8 @llvm.umax.i8(i8 %m1, i8 42) ret i8 %m2 } define <3 x i8> @umin_umin_reassoc_constant(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @umin_umin_reassoc_constant( ; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %x, <3 x i8> %y) %m2 = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %m1, <3 x i8> <i8 43, i8 -43, i8 0>) ret <3 x i8> %m2 } define i8 @umin_umin_reassoc_constant_use(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_umin_reassoc_constant_use( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umin.i8(i8 %x, i8 %y) call void @use(i8 %m1) %m2 = call i8 @llvm.umin.i8(i8 %m1, i8 42) ret i8 %m2 } define i8 @smax_smax_reassoc_constant_sink(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_smax_reassoc_constant_sink( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 42) %m2 = call i8 @llvm.smax.i8(i8 %m1, i8 %y) ret i8 %m2 } define <3 x i8> @smin_smin_reassoc_constant_sink(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smin_smin_reassoc_constant_sink( ; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %x, <3 x i8> <i8 43, i8 -43, i8 0>) %m2 = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %m1, <3 x i8> %y) ret <3 x i8> %m2 } define i8 @umax_umax_reassoc_constant_sink(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_umax_reassoc_constant_sink( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umax.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umax.i8(i8 %x, i8 42) %m2 = call i8 @llvm.umax.i8(i8 %m1, i8 %y) ret i8 %m2 } define <3 x i8> @umin_umin_reassoc_constant_sink(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @umin_umin_reassoc_constant_sink( ; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>) ; CHECK-NEXT: ret <3 x i8> [[M2]] ; %m1 = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %x, <3 x i8> <i8 43, i8 -43, i8 0>) %m2 = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %m1, <3 x i8> %y) ret <3 x i8> %m2 } define i8 @umin_umin_reassoc_constant_sink_use(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_umin_reassoc_constant_sink_use( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 42) ; CHECK-NEXT: call void @use(i8 [[M1]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[M1]], i8 [[Y:%.*]]) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umin.i8(i8 %x, i8 42) call void @use(i8 %m1) %m2 = call i8 @llvm.umin.i8(i8 %m1, i8 %y) ret i8 %m2 } define i8 @smax_smax_smax_reassoc_constants(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_smax_smax_reassoc_constants( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 126) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 42) %m2 = call i8 @llvm.smax.i8(i8 %y, i8 %m1) %m3 = call i8 @llvm.smax.i8(i8 %m2, i8 126) ret i8 %m3 } define i8 @smax_smax_smax_reassoc_constants_swap(i8 %x, i8 %y) { ; CHECK-LABEL: @smax_smax_smax_reassoc_constants_swap( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 126) ; CHECK-NEXT: ret i8 [[M3]] ; %m1 = call i8 @llvm.smax.i8(i8 %x, i8 42) %m2 = call i8 @llvm.smax.i8(i8 %m1, i8 %y) %m3 = call i8 @llvm.smax.i8(i8 %m2, i8 126) ret i8 %m3 } define i8 @smin_smin_smin_reassoc_constants(i8 %x, i8 %y) { ; CHECK-LABEL: @smin_smin_smin_reassoc_constants( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.smin.i8(i8 %x, i8 42) %m2 = call i8 @llvm.smin.i8(i8 %y, i8 %m1) %m3 = call i8 @llvm.smin.i8(i8 %m2, i8 126) ret i8 %m3 } define i8 @umax_umax_reassoc_constantexpr_sink(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_umax_reassoc_constantexpr_sink( ; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 ptrtoint (i8 (i8, i8)* @umax_umax_reassoc_constantexpr_sink to i8)) ; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umax.i8(i8 [[M1]], i8 42) ; CHECK-NEXT: ret i8 [[M2]] ; %m1 = call i8 @llvm.umax.i8(i8 %x, i8 42) %m2 = call i8 @llvm.umax.i8(i8 %m1, i8 ptrtoint (i8 (i8, i8)* @umax_umax_reassoc_constantexpr_sink to i8)) ret i8 %m2 } define <3 x i8> @smax_unary_shuffle_ops(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smax_unary_shuffle_ops( ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[R:%.*]] = shufflevector <3 x i8> [[TMP1]], <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> %sy = shufflevector <3 x i8> %y, <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } define <3 x i8> @smin_unary_shuffle_ops_use_poison_mask_elt(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smin_unary_shuffle_ops_use_poison_mask_elt( ; CHECK-NEXT: [[SX:%.*]] = shufflevector <3 x i8> [[X:%.*]], <3 x i8> poison, <3 x i32> <i32 undef, i32 0, i32 2> ; CHECK-NEXT: call void @use_vec(<3 x i8> [[SX]]) ; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[X]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[R:%.*]] = shufflevector <3 x i8> [[TMP1]], <3 x i8> poison, <3 x i32> <i32 undef, i32 0, i32 2> ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> poison, <3 x i32> <i32 poison, i32 0, i32 2> call void @use_vec(<3 x i8> %sx) %sy = shufflevector <3 x i8> %y, <3 x i8> poison, <3 x i32> <i32 poison, i32 0, i32 2> %r = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } define <3 x i8> @umax_unary_shuffle_ops_use_widening(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @umax_unary_shuffle_ops_use_widening( ; CHECK-NEXT: [[SY:%.*]] = shufflevector <2 x i8> [[Y:%.*]], <2 x i8> poison, <3 x i32> <i32 1, i32 0, i32 0> ; CHECK-NEXT: call void @use_vec(<3 x i8> [[SY]]) ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.umax.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y]]) ; CHECK-NEXT: [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> poison, <3 x i32> <i32 1, i32 0, i32 0> ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <2 x i8> %x, <2 x i8> poison, <3 x i32> <i32 1, i32 0, i32 0> %sy = shufflevector <2 x i8> %y, <2 x i8> poison, <3 x i32> <i32 1, i32 0, i32 0> call void @use_vec(<3 x i8> %sy) %r = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } define <3 x i8> @umin_unary_shuffle_ops_narrowing(<4 x i8> %x, <4 x i8> %y) { ; CHECK-LABEL: @umin_unary_shuffle_ops_narrowing( ; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i8> @llvm.umin.v4i8(<4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]]) ; CHECK-NEXT: [[R:%.*]] = shufflevector <4 x i8> [[TMP1]], <4 x i8> poison, <3 x i32> <i32 1, i32 0, i32 3> ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <4 x i8> %x, <4 x i8> poison, <3 x i32> <i32 1, i32 0, i32 3> %sy = shufflevector <4 x i8> %y, <4 x i8> poison, <3 x i32> <i32 1, i32 0, i32 3> %r = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } ; negative test - must have 2 shuffles define <3 x i8> @smax_unary_shuffle_ops_unshuffled_op(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smax_unary_shuffle_ops_unshuffled_op( ; CHECK-NEXT: [[SX:%.*]] = shufflevector <3 x i8> [[X:%.*]], <3 x i8> poison, <3 x i32> <i32 0, i32 0, i32 2> ; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[SX]], <3 x i8> [[Y:%.*]]) ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> poison, <3 x i32> <i32 0, i32 0, i32 2> %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %sx, <3 x i8> %y) ret <3 x i8> %r } ; negative test - must have identical masks define <3 x i8> @smax_unary_shuffle_ops_wrong_mask(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smax_unary_shuffle_ops_wrong_mask( ; CHECK-NEXT: [[SX:%.*]] = shufflevector <3 x i8> [[X:%.*]], <3 x i8> poison, <3 x i32> <i32 0, i32 0, i32 2> ; CHECK-NEXT: [[SY:%.*]] = shufflevector <3 x i8> [[Y:%.*]], <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> ; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[SX]], <3 x i8> [[SY]]) ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> poison, <3 x i32> <i32 0, i32 0, i32 2> %sy = shufflevector <3 x i8> %y, <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } ; negative test - must be unary shuffles define <3 x i8> @smax_unary_shuffle_ops_wrong_shuf(<3 x i8> %x, <3 x i8> %y, <3 x i8> %z) { ; CHECK-LABEL: @smax_unary_shuffle_ops_wrong_shuf( ; CHECK-NEXT: [[SX:%.*]] = shufflevector <3 x i8> [[X:%.*]], <3 x i8> [[Z:%.*]], <3 x i32> <i32 1, i32 0, i32 3> ; CHECK-NEXT: [[SY:%.*]] = shufflevector <3 x i8> [[Y:%.*]], <3 x i8> [[Z]], <3 x i32> <i32 1, i32 0, i32 3> ; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[SX]], <3 x i8> [[SY]]) ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> %z, <3 x i32> <i32 1, i32 0, i32 3> %sy = shufflevector <3 x i8> %y, <3 x i8> %z, <3 x i32> <i32 1, i32 0, i32 3> %r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r } ; negative test - too many uses define <3 x i8> @smin_unary_shuffle_ops_uses(<3 x i8> %x, <3 x i8> %y) { ; CHECK-LABEL: @smin_unary_shuffle_ops_uses( ; CHECK-NEXT: [[SX:%.*]] = shufflevector <3 x i8> [[X:%.*]], <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> ; CHECK-NEXT: call void @use_vec(<3 x i8> [[SX]]) ; CHECK-NEXT: [[SY:%.*]] = shufflevector <3 x i8> [[Y:%.*]], <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> ; CHECK-NEXT: call void @use_vec(<3 x i8> [[SY]]) ; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[SX]], <3 x i8> [[SY]]) ; CHECK-NEXT: ret <3 x i8> [[R]] ; %sx = shufflevector <3 x i8> %x, <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> call void @use_vec(<3 x i8> %sx) %sy = shufflevector <3 x i8> %y, <3 x i8> poison, <3 x i32> <i32 1, i32 0, i32 2> call void @use_vec(<3 x i8> %sy) %r = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %sx, <3 x i8> %sy) ret <3 x i8> %r }