A generalization like this was suggested in D119754. This is the inverse direction of D119851, and we get all of the folds there plus the one that was missed. There is precedence for this kind of transform in instcombine with "or" instructions (but strangely only with that one opcode AFAICT). Similar justification as in the other patch: The line between instcombine and reassociate for these kinds of folds is blurry. This doesn't appear to have much cost and gives us the expected wins from repeated folds as seen in the last set of test diffs. Differential Revision: https://reviews.llvm.org/D119955
2363 lines
75 KiB
LLVM
2363 lines
75 KiB
LLVM
; 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)
|
|
|
|
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
|
|
}
|