219 changes: 215 additions & 4 deletions llvm/test/CodeGen/AArch64/qmovn.ll
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ entry:
define <2 x i32> @vqmovni64_smaxmin(<2 x i64> %s0) {
; CHECK-LABEL: vqmovni64_smaxmin:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #2147483647
; CHECK-NEXT: mov w8, #2147483647 // =0x7fffffff
; CHECK-NEXT: dup v1.2d, x8
; CHECK-NEXT: mov x8, #-2147483648
; CHECK-NEXT: mov x8, #-2147483648 // =0xffffffff80000000
; CHECK-NEXT: cmgt v2.2d, v1.2d, v0.2d
; CHECK-NEXT: bif v0.16b, v1.16b, v2.16b
; CHECK-NEXT: dup v1.2d, x8
Expand All @@ -106,9 +106,9 @@ entry:
define <2 x i32> @vqmovni64_sminmax(<2 x i64> %s0) {
; CHECK-LABEL: vqmovni64_sminmax:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov x8, #-2147483648
; CHECK-NEXT: mov x8, #-2147483648 // =0xffffffff80000000
; CHECK-NEXT: dup v1.2d, x8
; CHECK-NEXT: mov w8, #2147483647
; CHECK-NEXT: mov w8, #2147483647 // =0x7fffffff
; CHECK-NEXT: cmgt v2.2d, v0.2d, v1.2d
; CHECK-NEXT: bif v0.16b, v1.16b, v2.16b
; CHECK-NEXT: dup v1.2d, x8
Expand Down Expand Up @@ -140,3 +140,214 @@ entry:
%t = trunc <2 x i64> %s1 to <2 x i32>
ret <2 x i32> %t
}

; Test the (concat_vectors (X), (trunc(smin(smax(Y, -2^n), 2^n-1))) pattern.

define <16 x i8> @signed_minmax_v8i16_to_v16i8(<8 x i8> %x, <8 x i16> %y) {
; CHECK-LABEL: signed_minmax_v8i16_to_v16i8:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: sqxtn2 v0.16b, v1.8h
; CHECK-NEXT: ret
entry:
%min = call <8 x i16> @llvm.smin.v8i16(<8 x i16> %y, <8 x i16> <i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127>)
%max = call <8 x i16> @llvm.smax.v8i16(<8 x i16> %min, <8 x i16> <i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128>)
%trunc = trunc <8 x i16> %max to <8 x i8>
%shuffle = shufflevector <8 x i8> %x, <8 x i8> %trunc, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
ret <16 x i8> %shuffle
}

define <8 x i16> @signed_minmax_v4i32_to_v8i16(<4 x i16> %x, <4 x i32> %y) {
; CHECK-LABEL: signed_minmax_v4i32_to_v8i16:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: sqxtn2 v0.8h, v1.4s
; CHECK-NEXT: ret
entry:
%min = call <4 x i32> @llvm.smin.v4i32(<4 x i32> %y, <4 x i32> <i32 32767, i32 32767, i32 32767, i32 32767>)
%max = call <4 x i32> @llvm.smax.v4i32(<4 x i32> %min, <4 x i32> <i32 -32768, i32 -32768, i32 -32768, i32 -32768>)
%trunc = trunc <4 x i32> %max to <4 x i16>
%shuffle = shufflevector <4 x i16> %x, <4 x i16> %trunc, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
ret <8 x i16> %shuffle
}

define <4 x i32> @signed_minmax_v2i64_to_v4i32(<2 x i32> %x, <2 x i64> %y) {
; CHECK-LABEL: signed_minmax_v2i64_to_v4i32:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #2147483647 // =0x7fffffff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: dup v2.2d, x8
; CHECK-NEXT: mov x8, #-2147483648 // =0xffffffff80000000
; CHECK-NEXT: cmgt v3.2d, v2.2d, v1.2d
; CHECK-NEXT: bif v1.16b, v2.16b, v3.16b
; CHECK-NEXT: dup v2.2d, x8
; CHECK-NEXT: cmgt v3.2d, v1.2d, v2.2d
; CHECK-NEXT: bif v1.16b, v2.16b, v3.16b
; CHECK-NEXT: xtn2 v0.4s, v1.2d
; CHECK-NEXT: ret
entry:
%min = call <2 x i64> @llvm.smin.v2i64(<2 x i64> %y, <2 x i64> <i64 2147483647, i64 2147483647>)
%max = call <2 x i64> @llvm.smax.v2i64(<2 x i64> %min, <2 x i64> <i64 -2147483648, i64 -2147483648>)
%trunc = trunc <2 x i64> %max to <2 x i32>
%shuffle = shufflevector <2 x i32> %x, <2 x i32> %trunc, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x i32> %shuffle
}

; Test the (concat_vectors (X), (trunc(smax(smin(Y, 2^n-1), -2^n))) pattern.

define <16 x i8> @signed_maxmin_v8i16_to_v16i8(<8 x i8> %x, <8 x i16> %y) {
; CHECK-LABEL: signed_maxmin_v8i16_to_v16i8:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: sqxtn2 v0.16b, v1.8h
; CHECK-NEXT: ret
entry:
%max = call <8 x i16> @llvm.smax.v8i16(<8 x i16> %y, <8 x i16> <i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128, i16 -128>)
%min = call <8 x i16> @llvm.smin.v8i16(<8 x i16> %max, <8 x i16> <i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127>)
%trunc = trunc <8 x i16> %min to <8 x i8>
%shuffle = shufflevector <8 x i8> %x, <8 x i8> %trunc, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
ret <16 x i8> %shuffle
}

define <8 x i16> @signed_maxmin_v4i32_to_v8i16(<4 x i16> %x, <4 x i32> %y) {
; CHECK-LABEL: signed_maxmin_v4i32_to_v8i16:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: sqxtn2 v0.8h, v1.4s
; CHECK-NEXT: ret
entry:
%max = call <4 x i32> @llvm.smax.v4i32(<4 x i32> %y, <4 x i32> <i32 -32768, i32 -32768, i32 -32768, i32 -32768>)
%min = call <4 x i32> @llvm.smin.v4i32(<4 x i32> %max, <4 x i32> <i32 32767, i32 32767, i32 32767, i32 32767>)
%trunc = trunc <4 x i32> %min to <4 x i16>
%shuffle = shufflevector <4 x i16> %x, <4 x i16> %trunc, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
ret <8 x i16> %shuffle
}

define <4 x i32> @signed_maxmin_v2i64_to_v4i32(<2 x i32> %x, <2 x i64> %y) {
; CHECK-LABEL: signed_maxmin_v2i64_to_v4i32:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov x8, #-2147483648 // =0xffffffff80000000
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: dup v2.2d, x8
; CHECK-NEXT: mov w8, #2147483647 // =0x7fffffff
; CHECK-NEXT: cmgt v3.2d, v1.2d, v2.2d
; CHECK-NEXT: bif v1.16b, v2.16b, v3.16b
; CHECK-NEXT: dup v2.2d, x8
; CHECK-NEXT: cmgt v3.2d, v2.2d, v1.2d
; CHECK-NEXT: bif v1.16b, v2.16b, v3.16b
; CHECK-NEXT: xtn2 v0.4s, v1.2d
; CHECK-NEXT: ret
entry:
%max = call <2 x i64> @llvm.smax.v2i64(<2 x i64> %y, <2 x i64> <i64 -2147483648, i64 -2147483648>)
%min = call <2 x i64> @llvm.smin.v2i64(<2 x i64> %max, <2 x i64> <i64 2147483647, i64 2147483647>)
%trunc = trunc <2 x i64> %min to <2 x i32>
%shuffle = shufflevector <2 x i32> %x, <2 x i32> %trunc, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x i32> %shuffle
}

; Test the (concat_vectors (X), (trunc(umin(Y, 2^n)))) pattern.

define <16 x i8> @unsigned_v8i16_to_v16i8(<8 x i8> %x, <8 x i16> %y) {
; CHECK-LABEL: unsigned_v8i16_to_v16i8:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.2d, #0xff00ff00ff00ff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: umin v1.8h, v1.8h, v2.8h
; CHECK-NEXT: xtn2 v0.16b, v1.8h
; CHECK-NEXT: ret
entry:
%min = call <8 x i16> @llvm.umin.v8i16(<8 x i16> %y, <8 x i16> <i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255>)
%trunc = trunc <8 x i16> %min to <8 x i8>
%shuffle = shufflevector <8 x i8> %x, <8 x i8> %trunc, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
ret <16 x i8> %shuffle
}

define <8 x i16> @unsigned_v4i32_to_v8i16(<4 x i16> %x, <4 x i32> %y) {
; CHECK-LABEL: unsigned_v4i32_to_v8i16:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.2d, #0x00ffff0000ffff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: umin v1.4s, v1.4s, v2.4s
; CHECK-NEXT: xtn2 v0.8h, v1.4s
; CHECK-NEXT: ret
entry:
%min = call <4 x i32> @llvm.umin.v4i32(<4 x i32> %y, <4 x i32> <i32 65535, i32 65535, i32 65535, i32 65535>)
%trunc = trunc <4 x i32> %min to <4 x i16>
%shuffle = shufflevector <4 x i16> %x, <4 x i16> %trunc, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
ret <8 x i16> %shuffle
}

define <4 x i32> @unsigned_v2i64_to_v4i32(<2 x i32> %x, <2 x i64> %y) {
; CHECK-LABEL: unsigned_v2i64_to_v4i32:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.2d, #0x000000ffffffff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: cmhi v2.2d, v2.2d, v1.2d
; CHECK-NEXT: and v1.16b, v1.16b, v2.16b
; CHECK-NEXT: orn v1.16b, v1.16b, v2.16b
; CHECK-NEXT: xtn2 v0.4s, v1.2d
; CHECK-NEXT: ret
entry:
%min = call <2 x i64> @llvm.umin.v2i64(<2 x i64> %y, <2 x i64> <i64 4294967295, i64 4294967295>)
%trunc = trunc <2 x i64> %min to <2 x i32>
%shuffle = shufflevector <2 x i32> %x, <2 x i32> %trunc, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x i32> %shuffle
}

; Test the (concat_vectors (X), (trunc(umin(smax(Y, 0), 2^n))))) pattern.

define <16 x i8> @us_maxmin_v8i16_to_v16i8(<8 x i8> %x, <8 x i16> %y) {
; CHECK-LABEL: us_maxmin_v8i16_to_v16i8:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.2d, #0000000000000000
; CHECK-NEXT: movi v3.2d, #0xff00ff00ff00ff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: smax v1.8h, v1.8h, v2.8h
; CHECK-NEXT: smin v1.8h, v1.8h, v3.8h
; CHECK-NEXT: xtn2 v0.16b, v1.8h
; CHECK-NEXT: ret
entry:
%max = call <8 x i16> @llvm.smax.v8i16(<8 x i16> %y, <8 x i16> zeroinitializer)
%min = call <8 x i16> @llvm.umin.v8i16(<8 x i16> %max, <8 x i16> <i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255>)
%trunc = trunc <8 x i16> %min to <8 x i8>
%shuffle = shufflevector <8 x i8> %x, <8 x i8> %trunc, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
ret <16 x i8> %shuffle
}

define <8 x i16> @us_maxmin_v4i32_to_v8i16(<4 x i16> %x, <4 x i32> %y) {
; CHECK-LABEL: us_maxmin_v4i32_to_v8i16:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.2d, #0000000000000000
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: smax v1.4s, v1.4s, v2.4s
; CHECK-NEXT: movi v2.2d, #0x00ffff0000ffff
; CHECK-NEXT: smin v1.4s, v1.4s, v2.4s
; CHECK-NEXT: xtn2 v0.8h, v1.4s
; CHECK-NEXT: ret
entry:
%max = call <4 x i32> @llvm.smax.v4i32(<4 x i32> %y, <4 x i32> zeroinitializer)
%min = call <4 x i32> @llvm.umin.v4i32(<4 x i32> %max, <4 x i32> <i32 65535, i32 65535, i32 65535, i32 65535>)
%trunc = trunc <4 x i32> %min to <4 x i16>
%shuffle = shufflevector <4 x i16> %x, <4 x i16> %trunc, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
ret <8 x i16> %shuffle
}

define <4 x i32> @us_maxmin_v2i64_to_v4i32(<2 x i32> %x, <2 x i64> %y) {
; CHECK-LABEL: us_maxmin_v2i64_to_v4i32:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: cmgt v2.2d, v1.2d, #0
; CHECK-NEXT: movi v3.2d, #0x000000ffffffff
; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT: and v1.16b, v1.16b, v2.16b
; CHECK-NEXT: cmgt v2.2d, v3.2d, v1.2d
; CHECK-NEXT: and v1.16b, v1.16b, v2.16b
; CHECK-NEXT: orn v1.16b, v1.16b, v2.16b
; CHECK-NEXT: xtn2 v0.4s, v1.2d
; CHECK-NEXT: ret
entry:
%max = call <2 x i64> @llvm.smax.v2i64(<2 x i64> %y, <2 x i64> zeroinitializer)
%min = call <2 x i64> @llvm.umin.v2i64(<2 x i64> %max, <2 x i64> <i64 4294967295, i64 4294967295>)
%trunc = trunc <2 x i64> %min to <2 x i32>
%shuffle = shufflevector <2 x i32> %x, <2 x i32> %trunc, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
ret <4 x i32> %shuffle
}