; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s target triple = "aarch64-unknown-linux-gnu" declare <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32>, <4 x i32>) declare <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32>, <4 x i32>) declare <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16>, <8 x i16>) declare <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16>, <8 x i16>) declare <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8>, <16 x i8>) declare <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8>, <16 x i8>) declare i64 @llvm.aarch64.neon.sshl.i64(i64, i64) declare i64 @llvm.aarch64.neon.ushl.i64(i64, i64) declare i32 @llvm.aarch64.neon.sshl.i32(i32, i32) declare i32 @llvm.aarch64.neon.ushl.i32(i32, i32) declare <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32>, <2 x i32>) declare <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32>, <2 x i32>) declare <4 x i16> @llvm.arm.neon.vshifts.v4i16(<4 x i16>, <4 x i16>) declare <4 x i16> @llvm.arm.neon.vshiftu.v4i16(<4 x i16>, <4 x i16>) declare <8 x i8> @llvm.arm.neon.vshifts.v8i8(<8 x i8>, <8 x i8>) declare <8 x i8> @llvm.arm.neon.vshiftu.v8i8(<8 x i8>, <8 x i8>) define <4 x i32> @sshl_positive_splat(<4 x i32> %a) { ; CHECK-LABEL: @sshl_positive_splat( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i32> [[A:%.*]], splat (i32 3) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @ushl_positive_splat(<4 x i32> %a) { ; CHECK-LABEL: @ushl_positive_splat( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i32> [[A:%.*]], splat (i32 7) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } ; Positive non-splat constants define <4 x i32> @ushl_positive_non_splat(<4 x i32> %a) { ; CHECK-LABEL: @ushl_positive_non_splat( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i32> [[A:%.*]], ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @sshl_zero(<4 x i32> %a) { ; CHECK-LABEL: @sshl_zero( ; CHECK-NEXT: ret <4 x i32> [[A:%.*]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> zeroinitializer) ret <4 x i32> %result } define <8 x i16> @sshl_i16_positive(<8 x i16> %a) { ; CHECK-LABEL: @sshl_i16_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl <8 x i16> [[A:%.*]], splat (i16 4) ; CHECK-NEXT: ret <8 x i16> [[RESULT]] ; %result = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 4)) ret <8 x i16> %result } define <16 x i8> @ushl_i8_positive(<16 x i8> %a) { ; CHECK-LABEL: @ushl_i8_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl <16 x i8> [[A:%.*]], splat (i8 2) ; CHECK-NEXT: ret <16 x i8> [[RESULT]] ; %result = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 2)) ret <16 x i8> %result } define <4 x i32> @sshl_negative_splat(<4 x i32> %a) { ; CHECK-LABEL: @sshl_negative_splat( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <4 x i32> [[A:%.*]], splat (i32 5) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 -5)) ret <4 x i32> %result } define <4 x i32> @sshl_negative_non_splat(<4 x i32> %a) { ; CHECK-LABEL: @sshl_negative_non_splat( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <4 x i32> [[A:%.*]], ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @ushl_negative_splat(<4 x i32> %a) { ; CHECK-LABEL: @ushl_negative_splat( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <4 x i32> [[A:%.*]], splat (i32 2) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 -2)) ret <4 x i32> %result } define <4 x i32> @ushl_negative_non_splat(<4 x i32> %a) { ; CHECK-LABEL: @ushl_negative_non_splat( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <4 x i32> [[A:%.*]], ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <8 x i16> @sshl_i16_negative(<8 x i16> %a) { ; CHECK-LABEL: @sshl_i16_negative( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <8 x i16> [[A:%.*]], splat (i16 3) ; CHECK-NEXT: ret <8 x i16> [[RESULT]] ; %result = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 -3)) ret <8 x i16> %result } define <16 x i8> @ushl_i8_negative(<16 x i8> %a) { ; CHECK-LABEL: @ushl_i8_negative( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <16 x i8> [[A:%.*]], splat (i8 1) ; CHECK-NEXT: ret <16 x i8> [[RESULT]] ; %result = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 -1)) ret <16 x i8> %result } define <4 x i32> @sshl_i32_max_left(<4 x i32> %a) { ; CHECK-LABEL: @sshl_i32_max_left( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i32> [[A:%.*]], splat (i32 31) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 31)) ret <4 x i32> %result } define <8 x i16> @ushl_i16_max_left(<8 x i16> %a) { ; CHECK-LABEL: @ushl_i16_max_left( ; CHECK-NEXT: [[RESULT:%.*]] = shl <8 x i16> [[A:%.*]], splat (i16 15) ; CHECK-NEXT: ret <8 x i16> [[RESULT]] ; %result = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 15)) ret <8 x i16> %result } define <16 x i8> @sshl_i8_max_left(<16 x i8> %a) { ; CHECK-LABEL: @sshl_i8_max_left( ; CHECK-NEXT: [[RESULT:%.*]] = shl <16 x i8> [[A:%.*]], splat (i8 7) ; CHECK-NEXT: ret <16 x i8> [[RESULT]] ; %result = call <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 7)) ret <16 x i8> %result } define <4 x i32> @ushl_i32_max_right(<4 x i32> %a) { ; CHECK-LABEL: @ushl_i32_max_right( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <4 x i32> [[A:%.*]], splat (i32 31) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 -31)) ret <4 x i32> %result } define <8 x i16> @sshl_i16_max_right(<8 x i16> %a) { ; CHECK-LABEL: @sshl_i16_max_right( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <8 x i16> [[A:%.*]], splat (i16 15) ; CHECK-NEXT: ret <8 x i16> [[RESULT]] ; %result = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 -15)) ret <8 x i16> %result } define <16 x i8> @ushl_i8_max_right(<16 x i8> %a) { ; CHECK-LABEL: @ushl_i8_max_right( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <16 x i8> [[A:%.*]], splat (i8 7) ; CHECK-NEXT: ret <16 x i8> [[RESULT]] ; %result = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 -7)) ret <16 x i8> %result } define i64 @sshl_scalar_positive(i64 %a) { ; CHECK-LABEL: @sshl_scalar_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl i64 [[A:%.*]], 5 ; CHECK-NEXT: ret i64 [[RESULT]] ; %result = call i64 @llvm.aarch64.neon.sshl.i64(i64 %a, i64 5) ret i64 %result } define i64 @ushl_scalar_negative(i64 %a) { ; CHECK-LABEL: @ushl_scalar_negative( ; CHECK-NEXT: [[RESULT:%.*]] = lshr i64 [[A:%.*]], 7 ; CHECK-NEXT: ret i64 [[RESULT]] ; %result = call i64 @llvm.aarch64.neon.ushl.i64(i64 %a, i64 -7) ret i64 %result } define i32 @sshl_i32_scalar_negative(i32 %a) { ; CHECK-LABEL: @sshl_i32_scalar_negative( ; CHECK-NEXT: [[RESULT:%.*]] = ashr i32 [[A:%.*]], 10 ; CHECK-NEXT: ret i32 [[RESULT]] ; %result = call i32 @llvm.aarch64.neon.sshl.i32(i32 %a, i32 -10) ret i32 %result } define i32 @ushl_i32_scalar_positive(i32 %a) { ; CHECK-LABEL: @ushl_i32_scalar_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl i32 [[A:%.*]], 8 ; CHECK-NEXT: ret i32 [[RESULT]] ; %result = call i32 @llvm.aarch64.neon.ushl.i32(i32 %a, i32 8) ret i32 %result } ;; Cases that should NOT be transformed define <4 x i32> @sshl_out_of_range_positive(<4 x i32> %a) { ; CHECK-LABEL: @sshl_out_of_range_positive( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> splat (i32 32)) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 32)) ret <4 x i32> %result } define <4 x i32> @ushl_out_of_range_negative(<4 x i32> %a) { ; CHECK-LABEL: @ushl_out_of_range_negative( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> splat (i32 -32)) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 -32)) ret <4 x i32> %result } define <8 x i16> @sshl_i16_out_of_range(<8 x i16> %a) { ; CHECK-LABEL: @sshl_i16_out_of_range( ; CHECK-NEXT: [[RESULT:%.*]] = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> [[A:%.*]], <8 x i16> splat (i16 16)) ; CHECK-NEXT: ret <8 x i16> [[RESULT]] ; %result = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 16)) ret <8 x i16> %result } define <16 x i8> @ushl_i8_out_of_range(<16 x i8> %a) { ; CHECK-LABEL: @ushl_i8_out_of_range( ; CHECK-NEXT: [[RESULT:%.*]] = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> [[A:%.*]], <16 x i8> splat (i8 -8)) ; CHECK-NEXT: ret <16 x i8> [[RESULT]] ; %result = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 -8)) ret <16 x i8> %result } define <4 x i32> @sshl_mixed_signs(<4 x i32> %a) { ; CHECK-LABEL: @sshl_mixed_signs( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> ) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @ushl_mixed_signs(<4 x i32> %a) { ; CHECK-LABEL: @ushl_mixed_signs( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> ) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @sshl_zero_and_negative(<4 x i32> %a) { ; CHECK-LABEL: @sshl_zero_and_negative( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> ) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @sshl_variable(<4 x i32> %a, <4 x i32> %shift) { ; CHECK-LABEL: @sshl_variable( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[SHIFT:%.*]]) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> %shift) ret <4 x i32> %result } define <4 x i32> @ushl_variable(<4 x i32> %a, <4 x i32> %shift) { ; CHECK-LABEL: @ushl_variable( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[SHIFT:%.*]]) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> %shift) ret <4 x i32> %result } define <4 x i32> @sshl_mixed_valid_invalid(<4 x i32> %a) { ; CHECK-LABEL: @sshl_mixed_valid_invalid( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> ) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <4 x i32> @ushl_mostly_negative_invalid(<4 x i32> %a) { ; CHECK-LABEL: @ushl_mostly_negative_invalid( ; CHECK-NEXT: [[RESULT:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> [[A:%.*]], <4 x i32> ) ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define i64 @sshl_scalar_out_of_range(i64 %a) { ; CHECK-LABEL: @sshl_scalar_out_of_range( ; CHECK-NEXT: [[RESULT:%.*]] = call i64 @llvm.aarch64.neon.sshl.i64(i64 [[A:%.*]], i64 64) ; CHECK-NEXT: ret i64 [[RESULT]] ; %result = call i64 @llvm.aarch64.neon.sshl.i64(i64 %a, i64 64) ret i64 %result } define i32 @ushl_scalar_out_of_range(i32 %a) { ; CHECK-LABEL: @ushl_scalar_out_of_range( ; CHECK-NEXT: [[RESULT:%.*]] = call i32 @llvm.aarch64.neon.ushl.i32(i32 [[A:%.*]], i32 -33) ; CHECK-NEXT: ret i32 [[RESULT]] ; %result = call i32 @llvm.aarch64.neon.ushl.i32(i32 %a, i32 -33) ret i32 %result } define <4 x i32> @sshl_positive_with_zero(<4 x i32> %a) { ; CHECK-LABEL: @sshl_positive_with_zero( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i32> [[A:%.*]], ; CHECK-NEXT: ret <4 x i32> [[RESULT]] ; %result = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> ) ret <4 x i32> %result } define <2 x i32> @vshifts_positive(<2 x i32> %a) { ; CHECK-LABEL: @vshifts_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl <2 x i32> [[A:%.*]], splat (i32 4) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result } define <2 x i32> @vshiftu_positive(<2 x i32> %a) { ; CHECK-LABEL: @vshiftu_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl <2 x i32> [[A:%.*]], splat (i32 3) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result } define <2 x i32> @vshifts_negative(<2 x i32> %a) { ; CHECK-LABEL: @vshifts_negative( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <2 x i32> [[A:%.*]], splat (i32 2) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result } define <2 x i32> @vshiftu_negative(<2 x i32> %a) { ; CHECK-LABEL: @vshiftu_negative( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <2 x i32> [[A:%.*]], splat (i32 5) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result } define <4 x i16> @vshifts_i16_positive(<4 x i16> %a) { ; CHECK-LABEL: @vshifts_i16_positive( ; CHECK-NEXT: [[RESULT:%.*]] = shl <4 x i16> [[A:%.*]], splat (i16 6) ; CHECK-NEXT: ret <4 x i16> [[RESULT]] ; %result = call <4 x i16> @llvm.arm.neon.vshifts.v4i16(<4 x i16> %a, <4 x i16> ) ret <4 x i16> %result } define <4 x i16> @vshiftu_i16_negative(<4 x i16> %a) { ; CHECK-LABEL: @vshiftu_i16_negative( ; CHECK-NEXT: [[RESULT:%.*]] = lshr <4 x i16> [[A:%.*]], splat (i16 8) ; CHECK-NEXT: ret <4 x i16> [[RESULT]] ; %result = call <4 x i16> @llvm.arm.neon.vshiftu.v4i16(<4 x i16> %a, <4 x i16> ) ret <4 x i16> %result } define <8 x i8> @vshifts_i8_negative(<8 x i8> %a) { ; CHECK-LABEL: @vshifts_i8_negative( ; CHECK-NEXT: [[RESULT:%.*]] = ashr <8 x i8> [[A:%.*]], splat (i8 3) ; CHECK-NEXT: ret <8 x i8> [[RESULT]] ; %result = call <8 x i8> @llvm.arm.neon.vshifts.v8i8(<8 x i8> %a, <8 x i8> ) ret <8 x i8> %result } define <2 x i32> @vshifts_out_of_range(<2 x i32> %a) { ; CHECK-LABEL: @vshifts_out_of_range( ; CHECK-NEXT: [[RESULT:%.*]] = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> [[A:%.*]], <2 x i32> splat (i32 32)) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result } define <2 x i32> @vshiftu_mixed_signs(<2 x i32> %a) { ; CHECK-LABEL: @vshiftu_mixed_signs( ; CHECK-NEXT: [[RESULT:%.*]] = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> [[A:%.*]], <2 x i32> ) ; CHECK-NEXT: ret <2 x i32> [[RESULT]] ; %result = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> %a, <2 x i32> ) ret <2 x i32> %result }