; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=aarch64 | FileCheck %s ;; ============================================================================ ;; Tests for canCreateUndefOrPoison = false ;; These verify that freeze operations are correctly eliminated ;; ============================================================================ ; TRUNCATE_SSAT_S: No saturation path define i1 @sqxtn_no_sat_with_freeze(<4 x i32> %x) { ; CHECK-LABEL: sqxtn_no_sat_with_freeze: ; CHECK: // %bb.0: ; CHECK-NEXT: movi v1.4s, #100 ; CHECK-NEXT: and v0.16b, v0.16b, v1.16b ; CHECK-NEXT: sqxtn v0.4h, v0.4s ; CHECK-NEXT: umov w8, v0.h[0] ; CHECK-NEXT: and w8, w8, #0xfffc ; CHECK-NEXT: cmp w8, #200 ; CHECK-NEXT: cset w0, gt ; CHECK-NEXT: ret %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %masked) %freeze = freeze <4 x i16> %trunc %extract = extractelement <4 x i16> %freeze, i32 0 ; Input is [0,100], so result > 200 is always false %cmp = icmp sgt i16 %extract, 200 ret i1 %cmp } ; TRUNCATE_SSAT_S: Test specific known bits define i16 @sqxtn_known_bits(<4 x i32> %x) { ; CHECK-LABEL: sqxtn_known_bits: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret ; Input: [0, 32512] fits in i16 without saturation %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %masked) %freeze = freeze <4 x i16> %trunc %extract = extractelement <4 x i16> %freeze, i32 0 ; Mask to lower 7 bits - with KnownBits, knows upper bits are already 0 ; so this AND can be simplified %and = and i16 %extract, 127 ret i16 %and } ;; ============================================================================ ;; Tests for computeKnownBits ;; These verify that known bits analysis enables optimizations ;; TRUNCATE_SSAT_S: Signed to Signed Saturating Truncate (sqxtn) ;; ============================================================================ ; Constant 32512 = 0b0111111110000000 has known zero lower bits ; After truncation, ANDing with 127 (lower 7 bits) gives 0 define i16 @sqxtn_known_zero_bits(<4 x i32> %x) { ; CHECK-LABEL: sqxtn_known_zero_bits: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %masked) %extract = extractelement <4 x i16> %trunc, i32 0 %and = and i16 %extract, 127 ret i16 %and } ; Input range [0, 256] means result is always non-negative ; Comparison with negative value should fold to false (returns 0) define i1 @sqxtn_known_nonnegative(<4 x i32> %x) { ; CHECK-LABEL: sqxtn_known_nonnegative: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %masked) %extract = extractelement <4 x i16> %trunc, i32 0 %cmp = icmp slt i16 %extract, 0 ret i1 %cmp } ;; ============================================================================ ;; TRUNCATE_SSAT_U: Signed to Unsigned Saturating Truncate (sqxtun) ;; ============================================================================ define i16 @sqxtun_known_zero_lower_bits(<4 x i32> %x) { ; CHECK-LABEL: sqxtun_known_zero_lower_bits: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %masked) %extract = extractelement <4 x i16> %trunc, i32 0 %and = and i16 %extract, 255 ret i16 %and } define i16 @sqxtun_known_zero_upper_bits(<4 x i32> %x) { ; CHECK-LABEL: sqxtun_known_zero_upper_bits: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret %masked = and <4 x i32> %x, %trunc = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %masked) %extract = extractelement <4 x i16> %trunc, i32 0 %shift = lshr i16 %extract, 7 ret i16 %shift } ;; ============================================================================ ;; TRUNCATE_USAT_U: Unsigned to Unsigned Saturating Truncate (uqxtn) ;; ============================================================================ define i8 @uqxtn_known_zero_upper_bits(<8 x i16> %x) { ; CHECK-LABEL: uqxtn_known_zero_upper_bits: ; CHECK: // %bb.0: ; CHECK-NEXT: mov w0, wzr ; CHECK-NEXT: ret %masked = and <8 x i16> %x, %trunc = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> %masked) %extract = extractelement <8 x i8> %trunc, i32 0 %shift = lshr i8 %extract, 6 ret i8 %shift } declare <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32>) declare <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32>) declare <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16>)