https://github.com/kieroxide created https://github.com/llvm/llvm-project/pull/212459
- Add ImmCheckShiftLeftLong to allow checking of [0..((elt/2) -1)] range checks - Add immediate range checks in vector-shift-left.c - Update stale intrinsic tests for vcvt_f32_bf16 and vshll_n - Add GIsel patterns so VCVT_F32_BF16 lowers to the correct ACLE specified instruction The fixed immediate range caused a problem with the VCVT_F32_BF16 instrinic as it used vshll_n with an illegal range immediate of 16. I split this instruction into a widen (vmovl) then a shift (vshl_n) producing the same result. Both A64/A32 lower to the vshll/shll 16 widen-shift instruction in asm as defined in ACLE. Tests for the vshll_n fold can be found in vshll.ll (A32) and arm64-vshift.ll (A64) >From b61f7758eaceecd6e7b5f5474d39af3c6a84aada Mon Sep 17 00:00:00 2001 From: Kieran Bailey <[email protected]> Date: Tue, 28 Jul 2026 09:31:59 +0000 Subject: [PATCH] [Clang][ARM] Fix immediate range for NEON widening left-shifts - Add ImmCheckShiftLeftLong to allow checking of [0..((elt/2) -1)] range checks - Add immediate range checks in vector-shift-left.c - Update stale intrinsic tests for vcvt_f32_bf16 and vshll_n - Add GIsel patterns so VCVT_F32_BF16 lowers to the correct ACLE specified instruction The fixed immediate range caused a problem with the VCVT_F32_BF16 instrinic as it used vshll_n with an illegal range immediate of 16. I split this instruction into a widen (vmovl) then a shift (vshl_n) producing the same result. Both A64/A32 lower to the vshll/shll 16 widen-shift instruction in asm as defined in ACLE. Tests for the vshll_n fold can be found in vshll.ll (A32) and arm64-vshift.ll (A64) --- .../include/clang/Basic/arm_immcheck_incl.td | 43 ++++----- clang/include/clang/Basic/arm_neon.td | 19 ++-- clang/lib/Sema/SemaARM.cpp | 5 ++ clang/test/CodeGen/AArch64/neon-misc.c | 48 +++++----- .../CodeGen/arm-bf16-convert-intrinsics.c | 90 +++++++++++-------- .../vector-shift-left.c | 45 +++------- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 5 ++ llvm/test/CodeGen/AArch64/arm64-vcvt_f.ll | 54 +++++++++++ llvm/test/CodeGen/AArch64/arm64-vshift.ll | 14 +-- 9 files changed, 190 insertions(+), 133 deletions(-) diff --git a/clang/include/clang/Basic/arm_immcheck_incl.td b/clang/include/clang/Basic/arm_immcheck_incl.td index 6892b8299771b..87bc83e89aa10 100644 --- a/clang/include/clang/Basic/arm_immcheck_incl.td +++ b/clang/include/clang/Basic/arm_immcheck_incl.td @@ -11,27 +11,28 @@ def ImmCheckExtract : ImmCheckType<2>; // 0..(2048/sizeinbits(elt) def ImmCheckShiftRight : ImmCheckType<3>; // 1..sizeinbits(elt) def ImmCheckShiftRightNarrow : ImmCheckType<4>; // 1..sizeinbits(elt)/2 def ImmCheckShiftLeft : ImmCheckType<5>; // 0..(sizeinbits(elt) - 1) -def ImmCheck0_7 : ImmCheckType<6>; // 0..7 -def ImmCheckLaneIndex : ImmCheckType<7>; // 0..(container_size/(sizeinbits(elt)) - 1) -def ImmCheckCvt : ImmCheckType<8>; // 1..sizeinbits(elt) (same as ShiftRight) -def ImmCheckLaneIndexCompRotate : ImmCheckType<9>; // 0..(container_size/(2*sizeinbits(elt)) - 1) -def ImmCheckLaneIndexDot : ImmCheckType<10>; // 0..(container_size/(4*sizeinbits(elt)) - 1) -def ImmCheckComplexRot90_270 : ImmCheckType<11>; // [90,270] -def ImmCheckComplexRotAll90 : ImmCheckType<12>; // [0, 90, 180,270] -def ImmCheck0_13 : ImmCheckType<13>; // 0..13 -def ImmCheck0_1 : ImmCheckType<14>; // 0..1 -def ImmCheck0_2 : ImmCheckType<15>; // 0..2 -def ImmCheck0_3 : ImmCheckType<16>; // 0..3 -def ImmCheck0_0 : ImmCheckType<17>; // 0..0 -def ImmCheck0_15 : ImmCheckType<18>; // 0..15 -def ImmCheck0_255 : ImmCheckType<19>; // 0..255 -def ImmCheck2_4_Mul2 : ImmCheckType<20>; // 2, 4 -def ImmCheck1_1 : ImmCheckType<21>; // 1..1 -def ImmCheck1_3 : ImmCheckType<22>; // 1..3 -def ImmCheck1_7 : ImmCheckType<23>; // 1..7 -def ImmCheck1_32 : ImmCheckType<24>; // 1..32 -def ImmCheck1_64 : ImmCheckType<25>; // 1..64 -def ImmCheck0_63 : ImmCheckType<26>; // 0..63 +def ImmCheckShiftLeftLong : ImmCheckType<6>; // 0..(sizeinbits(elt)/2) - 1) +def ImmCheck0_7 : ImmCheckType<7>; // 0..7 +def ImmCheckLaneIndex : ImmCheckType<8>; // 0..(container_size/(sizeinbits(elt)) - 1) +def ImmCheckCvt : ImmCheckType<9>; // 1..sizeinbits(elt) (same as ShiftRight) +def ImmCheckLaneIndexCompRotate : ImmCheckType<10>; // 0..(container_size/(2*sizeinbits(elt)) - 1) +def ImmCheckLaneIndexDot : ImmCheckType<11>; // 0..(container_size/(4*sizeinbits(elt)) - 1) +def ImmCheckComplexRot90_270 : ImmCheckType<12>; // [90,270] +def ImmCheckComplexRotAll90 : ImmCheckType<13>; // [0, 90, 180,270] +def ImmCheck0_13 : ImmCheckType<14>; // 0..13 +def ImmCheck0_1 : ImmCheckType<15>; // 0..1 +def ImmCheck0_2 : ImmCheckType<16>; // 0..2 +def ImmCheck0_3 : ImmCheckType<17>; // 0..3 +def ImmCheck0_0 : ImmCheckType<18>; // 0..0 +def ImmCheck0_15 : ImmCheckType<19>; // 0..15 +def ImmCheck0_255 : ImmCheckType<20>; // 0..255 +def ImmCheck2_4_Mul2 : ImmCheckType<21>; // 2, 4 +def ImmCheck1_1 : ImmCheckType<22>; // 1..1 +def ImmCheck1_3 : ImmCheckType<23>; // 1..3 +def ImmCheck1_7 : ImmCheckType<24>; // 1..7 +def ImmCheck1_32 : ImmCheckType<25>; // 1..32 +def ImmCheck1_64 : ImmCheckType<26>; // 1..64 +def ImmCheck0_63 : ImmCheckType<27>; // 0..63 class ImmCheck<int immArgIdx, ImmCheckType kind, int typeArgIdx = -1> { // Parameter index of immediate argument to be verified diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td index 041a420875290..e7008b39f202d 100644 --- a/clang/include/clang/Basic/arm_neon.td +++ b/clang/include/clang/Basic/arm_neon.td @@ -251,9 +251,10 @@ def OP_BFMLALT_LN (dup_typed $p1, (call "vget_lane", $p2, $p3)))>; def OP_VCVT_F32_BF16 - : Op<(bitcast "R", - (call "vshll_n", (bitcast "uint16x4_t", $p0), - (literal "int32_t", "16")))>; + : Op<(bitcast "R", + (call "vshl_n", + (call "vmovl", (bitcast "uint16x4_t", $p0)), + (literal "int32_t", "16")))>; def OP_VCVT_F32_BF16_LO : Op<(call "vcvt_f32_bf16", (call "vget_low", $p0))>; def OP_VCVT_F32_BF16_HI @@ -432,13 +433,13 @@ def VRSHRN_N : IInst<"vrshrn_n", "<QI", "silUsUiUl", def VQRSHRN_N : SInst<"vqrshrn_n", "<QI", "silUsUiUl", [ImmCheck<1, ImmCheckShiftRight>]>; -// Widening left-shifts should have a range of 0..(sizeinbits(arg)-1). -// This polymorphic builtin is supplied the wider return type as it's overloaded -// base type, so the range here is actually 0..(sizeinbits(arg)*2). -// This cannot be rectified currently due to a use of vshll_n_s16 with an -// out-of-bounds immediate in the defintiion of vcvt_f32_bf16. +// Widening left-shifts should have an immediate range of 0..(sizeinbits(arg)-1). +// However, as the overloaded type code that is supplied to a polymorphic builtin +// is that of the return type (twice as wide as the argument in this case), using +// ImmCheckShiftLeft would return in an upper bound of ((sizeinbits(arg)*2)-1). +// ImmCheckShiftLeftLong produces the correct behavior here. def VSHLL_N : SInst<"vshll_n", "(>Q).I", "csiUcUsUi", - [ImmCheck<1, ImmCheckShiftLeft>]>; + [ImmCheck<1, ImmCheckShiftLeftLong>]>; //////////////////////////////////////////////////////////////////////////////// // E.3.13 Shifts with insert diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index 5e7504fab416d..d801ff17ce2f4 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -452,6 +452,11 @@ bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy, if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, EltBitWidth - 1)) return true; break; + case ImmCheckType::ImmCheckShiftLeftLong: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, + (EltBitWidth / 2) - 1)) + return true; + break; case ImmCheckType::ImmCheckLaneIndex: if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, (ContainerBitWidth / EltBitWidth) - 1)) diff --git a/clang/test/CodeGen/AArch64/neon-misc.c b/clang/test/CodeGen/AArch64/neon-misc.c index 308718fd1bedf..e9e17b2fe407a 100644 --- a/clang/test/CodeGen/AArch64/neon-misc.c +++ b/clang/test/CodeGen/AArch64/neon-misc.c @@ -2451,11 +2451,11 @@ uint32x4_t test_vqmovn_high_u64(uint32x2_t a, uint64x2_t b) { // CHECK-SAME: <8 x i8> noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = sext <8 x i8> [[A]] to <8 x i16> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 8) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 7) // CHECK-NEXT: ret <8 x i16> [[VSHLL_N]] // int16x8_t test_vshll_n_s8(int8x8_t a) { - return vshll_n_s8(a, 8); + return vshll_n_s8(a, 7); } // CHECK-LABEL: define dso_local <4 x i32> @test_vshll_n_s16( @@ -2464,11 +2464,11 @@ int16x8_t test_vshll_n_s8(int8x8_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i16> [[A]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16> // CHECK-NEXT: [[TMP2:%.*]] = sext <4 x i16> [[TMP1]] to <4 x i32> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 16) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 15) // CHECK-NEXT: ret <4 x i32> [[VSHLL_N]] // int32x4_t test_vshll_n_s16(int16x4_t a) { - return vshll_n_s16(a, 16); + return vshll_n_s16(a, 15); } // CHECK-LABEL: define dso_local <2 x i64> @test_vshll_n_s32( @@ -2477,22 +2477,22 @@ int32x4_t test_vshll_n_s16(int16x4_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i32> [[A]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32> // CHECK-NEXT: [[TMP2:%.*]] = sext <2 x i32> [[TMP1]] to <2 x i64> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 32) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 31) // CHECK-NEXT: ret <2 x i64> [[VSHLL_N]] // int64x2_t test_vshll_n_s32(int32x2_t a) { - return vshll_n_s32(a, 32); + return vshll_n_s32(a, 31); } // CHECK-LABEL: define dso_local <8 x i16> @test_vshll_n_u8( // CHECK-SAME: <8 x i8> noundef [[A:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = zext <8 x i8> [[A]] to <8 x i16> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 8) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 7) // CHECK-NEXT: ret <8 x i16> [[VSHLL_N]] // uint16x8_t test_vshll_n_u8(uint8x8_t a) { - return vshll_n_u8(a, 8); + return vshll_n_u8(a, 7); } // CHECK-LABEL: define dso_local <4 x i32> @test_vshll_n_u16( @@ -2501,11 +2501,11 @@ uint16x8_t test_vshll_n_u8(uint8x8_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i16> [[A]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16> // CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 16) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 15) // CHECK-NEXT: ret <4 x i32> [[VSHLL_N]] // uint32x4_t test_vshll_n_u16(uint16x4_t a) { - return vshll_n_u16(a, 16); + return vshll_n_u16(a, 15); } // CHECK-LABEL: define dso_local <2 x i64> @test_vshll_n_u32( @@ -2514,11 +2514,11 @@ uint32x4_t test_vshll_n_u16(uint16x4_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i32> [[A]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32> // CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 32) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 31) // CHECK-NEXT: ret <2 x i64> [[VSHLL_N]] // uint64x2_t test_vshll_n_u32(uint32x2_t a) { - return vshll_n_u32(a, 32); + return vshll_n_u32(a, 31); } // CHECK-LABEL: define dso_local <8 x i16> @test_vshll_high_n_s8( @@ -2526,11 +2526,11 @@ uint64x2_t test_vshll_n_u32(uint32x2_t a) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <16 x i8> [[A]], <16 x i8> [[A]], <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> // CHECK-NEXT: [[TMP0:%.*]] = sext <8 x i8> [[SHUFFLE_I]] to <8 x i16> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 8) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 7) // CHECK-NEXT: ret <8 x i16> [[VSHLL_N]] // int16x8_t test_vshll_high_n_s8(int8x16_t a) { - return vshll_high_n_s8(a, 8); + return vshll_high_n_s8(a, 7); } // CHECK-LABEL: define dso_local <4 x i32> @test_vshll_high_n_s16( @@ -2540,11 +2540,11 @@ int16x8_t test_vshll_high_n_s8(int8x16_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16> // CHECK-NEXT: [[TMP2:%.*]] = sext <4 x i16> [[TMP1]] to <4 x i32> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 16) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 15) // CHECK-NEXT: ret <4 x i32> [[VSHLL_N]] // int32x4_t test_vshll_high_n_s16(int16x8_t a) { - return vshll_high_n_s16(a, 16); + return vshll_high_n_s16(a, 15); } // CHECK-LABEL: define dso_local <2 x i64> @test_vshll_high_n_s32( @@ -2554,11 +2554,11 @@ int32x4_t test_vshll_high_n_s16(int16x8_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32> // CHECK-NEXT: [[TMP2:%.*]] = sext <2 x i32> [[TMP1]] to <2 x i64> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 32) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 31) // CHECK-NEXT: ret <2 x i64> [[VSHLL_N]] // int64x2_t test_vshll_high_n_s32(int32x4_t a) { - return vshll_high_n_s32(a, 32); + return vshll_high_n_s32(a, 31); } // CHECK-LABEL: define dso_local <8 x i16> @test_vshll_high_n_u8( @@ -2566,11 +2566,11 @@ int64x2_t test_vshll_high_n_s32(int32x4_t a) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <16 x i8> [[A]], <16 x i8> [[A]], <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> // CHECK-NEXT: [[TMP0:%.*]] = zext <8 x i8> [[SHUFFLE_I]] to <8 x i16> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 8) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <8 x i16> [[TMP0]], splat (i16 7) // CHECK-NEXT: ret <8 x i16> [[VSHLL_N]] // uint16x8_t test_vshll_high_n_u8(uint8x16_t a) { - return vshll_high_n_u8(a, 8); + return vshll_high_n_u8(a, 7); } // CHECK-LABEL: define dso_local <4 x i32> @test_vshll_high_n_u16( @@ -2580,11 +2580,11 @@ uint16x8_t test_vshll_high_n_u8(uint8x16_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16> // CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 16) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <4 x i32> [[TMP2]], splat (i32 15) // CHECK-NEXT: ret <4 x i32> [[VSHLL_N]] // uint32x4_t test_vshll_high_n_u16(uint16x8_t a) { - return vshll_high_n_u16(a, 16); + return vshll_high_n_u16(a, 15); } // CHECK-LABEL: define dso_local <2 x i64> @test_vshll_high_n_u32( @@ -2594,11 +2594,11 @@ uint32x4_t test_vshll_high_n_u16(uint16x8_t a) { // CHECK-NEXT: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8> // CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32> // CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 32) +// CHECK-NEXT: [[VSHLL_N:%.*]] = shl <2 x i64> [[TMP2]], splat (i64 31) // CHECK-NEXT: ret <2 x i64> [[VSHLL_N]] // uint64x2_t test_vshll_high_n_u32(uint32x4_t a) { - return vshll_high_n_u32(a, 32); + return vshll_high_n_u32(a, 31); } // CHECK-LABEL: define dso_local <4 x half> @test_vcvt_f16_f32( diff --git a/clang/test/CodeGen/arm-bf16-convert-intrinsics.c b/clang/test/CodeGen/arm-bf16-convert-intrinsics.c index 8a1ef2441b39d..256c681db3b3f 100644 --- a/clang/test/CodeGen/arm-bf16-convert-intrinsics.c +++ b/clang/test/CodeGen/arm-bf16-convert-intrinsics.c @@ -27,20 +27,24 @@ // CHECK-A64-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[A:%.*]] to <4 x i16> // CHECK-A64-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A64-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A64-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A64-NEXT: [[VSHLL_N_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I]] to <4 x float> -// CHECK-A64-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A64-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A64-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A64-NEXT: [[VSHL_N_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A64-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I]] to <4 x float> +// CHECK-A64-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-HARDFP-LABEL: @test_vcvt_f32_bf16( // CHECK-A32-HARDFP-NEXT: entry: // CHECK-A32-HARDFP-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[A:%.*]] to <4 x i16> // CHECK-A32-HARDFP-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A32-HARDFP-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A32-HARDFP-NEXT: [[VSHLL_N_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I]] to <4 x float> -// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A32-HARDFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[VSHL_N_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A32-HARDFP-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I]] to <4 x float> +// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-SOFTFP-LABEL: @test_vcvt_f32_bf16( // CHECK-A32-SOFTFP-NEXT: entry: @@ -50,10 +54,12 @@ // CHECK-A32-SOFTFP-NEXT: [[TMP3:%.*]] = bitcast <4 x bfloat> [[TMP2]] to <4 x i16> // CHECK-A32-SOFTFP-NEXT: [[TMP4:%.*]] = bitcast <4 x i16> [[TMP3]] to <8 x i8> // CHECK-A32-SOFTFP-NEXT: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> -// CHECK-A32-SOFTFP-NEXT: [[TMP6:%.*]] = zext <4 x i16> [[TMP5]] to <4 x i32> -// CHECK-A32-SOFTFP-NEXT: [[VSHLL_N_I:%.*]] = shl <4 x i32> [[TMP6]], splat (i32 16) -// CHECK-A32-SOFTFP-NEXT: [[TMP7:%.*]] = bitcast <4 x i32> [[VSHLL_N_I]] to <4 x float> -// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP7]] +// CHECK-A32-SOFTFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP5]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[TMP6:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-SOFTFP-NEXT: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP6]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[VSHL_N_I:%.*]] = shl <4 x i32> [[TMP7]], splat (i32 16) +// CHECK-A32-SOFTFP-NEXT: [[TMP8:%.*]] = bitcast <4 x i32> [[VSHL_N_I]] to <4 x float> +// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP8]] // float32x4_t test_vcvt_f32_bf16(bfloat16x4_t a) { return vcvt_f32_bf16(a); @@ -65,10 +71,12 @@ float32x4_t test_vcvt_f32_bf16(bfloat16x4_t a) { // CHECK-A64-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[SHUFFLE_I]] to <4 x i16> // CHECK-A64-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A64-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A64-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A64-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A64-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A64-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A64-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A64-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A64-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A64-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-HARDFP-LABEL: @test_vcvtq_low_f32_bf16( // CHECK-A32-HARDFP-NEXT: entry: @@ -76,10 +84,12 @@ float32x4_t test_vcvt_f32_bf16(bfloat16x4_t a) { // CHECK-A32-HARDFP-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[SHUFFLE_I]] to <4 x i16> // CHECK-A32-HARDFP-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A32-HARDFP-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A32-HARDFP-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A32-HARDFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A32-HARDFP-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-SOFTFP-LABEL: @test_vcvtq_low_f32_bf16( // CHECK-A32-SOFTFP-NEXT: entry: @@ -96,10 +106,12 @@ float32x4_t test_vcvt_f32_bf16(bfloat16x4_t a) { // CHECK-A32-SOFTFP-NEXT: [[TMP9:%.*]] = bitcast <4 x bfloat> [[TMP8]] to <4 x i16> // CHECK-A32-SOFTFP-NEXT: [[TMP10:%.*]] = bitcast <4 x i16> [[TMP9]] to <8 x i8> // CHECK-A32-SOFTFP-NEXT: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> -// CHECK-A32-SOFTFP-NEXT: [[TMP12:%.*]] = zext <4 x i16> [[TMP11]] to <4 x i32> -// CHECK-A32-SOFTFP-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP12]], splat (i32 16) -// CHECK-A32-SOFTFP-NEXT: [[TMP13:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP13]] +// CHECK-A32-SOFTFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP11]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[TMP12:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-SOFTFP-NEXT: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP12]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP13]], splat (i32 16) +// CHECK-A32-SOFTFP-NEXT: [[TMP14:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP14]] // float32x4_t test_vcvtq_low_f32_bf16(bfloat16x8_t a) { return vcvtq_low_f32_bf16(a); @@ -111,10 +123,12 @@ float32x4_t test_vcvtq_low_f32_bf16(bfloat16x8_t a) { // CHECK-A64-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[SHUFFLE_I]] to <4 x i16> // CHECK-A64-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A64-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A64-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A64-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A64-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A64-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A64-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A64-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A64-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A64-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A64-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-HARDFP-LABEL: @test_vcvtq_high_f32_bf16( // CHECK-A32-HARDFP-NEXT: entry: @@ -122,10 +136,12 @@ float32x4_t test_vcvtq_low_f32_bf16(bfloat16x8_t a) { // CHECK-A32-HARDFP-NEXT: [[TMP0:%.*]] = bitcast <4 x bfloat> [[SHUFFLE_I]] to <4 x i16> // CHECK-A32-HARDFP-NEXT: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8> // CHECK-A32-HARDFP-NEXT: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> -// CHECK-A32-HARDFP-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP3]], splat (i32 16) -// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP4]] +// CHECK-A32-HARDFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-HARDFP-NEXT: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32> +// CHECK-A32-HARDFP-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP4]], splat (i32 16) +// CHECK-A32-HARDFP-NEXT: [[TMP5:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A32-HARDFP-NEXT: ret <4 x float> [[TMP5]] // // CHECK-A32-SOFTFP-LABEL: @test_vcvtq_high_f32_bf16( // CHECK-A32-SOFTFP-NEXT: entry: @@ -142,10 +158,12 @@ float32x4_t test_vcvtq_low_f32_bf16(bfloat16x8_t a) { // CHECK-A32-SOFTFP-NEXT: [[TMP9:%.*]] = bitcast <4 x bfloat> [[TMP8]] to <4 x i16> // CHECK-A32-SOFTFP-NEXT: [[TMP10:%.*]] = bitcast <4 x i16> [[TMP9]] to <8 x i8> // CHECK-A32-SOFTFP-NEXT: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> -// CHECK-A32-SOFTFP-NEXT: [[TMP12:%.*]] = zext <4 x i16> [[TMP11]] to <4 x i32> -// CHECK-A32-SOFTFP-NEXT: [[VSHLL_N_I_I:%.*]] = shl <4 x i32> [[TMP12]], splat (i32 16) -// CHECK-A32-SOFTFP-NEXT: [[TMP13:%.*]] = bitcast <4 x i32> [[VSHLL_N_I_I]] to <4 x float> -// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP13]] +// CHECK-A32-SOFTFP-NEXT: [[VMOVL_I:%.*]] = zext <4 x i16> [[TMP11]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[TMP12:%.*]] = bitcast <4 x i32> [[VMOVL_I]] to <16 x i8> +// CHECK-A32-SOFTFP-NEXT: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP12]] to <4 x i32> +// CHECK-A32-SOFTFP-NEXT: [[VSHL_N_I_I:%.*]] = shl <4 x i32> [[TMP13]], splat (i32 16) +// CHECK-A32-SOFTFP-NEXT: [[TMP14:%.*]] = bitcast <4 x i32> [[VSHL_N_I_I]] to <4 x float> +// CHECK-A32-SOFTFP-NEXT: ret <4 x float> [[TMP14]] // float32x4_t test_vcvtq_high_f32_bf16(bfloat16x8_t a) { return vcvtq_high_f32_bf16(a); diff --git a/clang/test/Sema/aarch64-neon-immediate-ranges/vector-shift-left.c b/clang/test/Sema/aarch64-neon-immediate-ranges/vector-shift-left.c index 1def72fc843d9..ce0da4419d184 100644 --- a/clang/test/Sema/aarch64-neon-immediate-ranges/vector-shift-left.c +++ b/clang/test/Sema/aarch64-neon-immediate-ranges/vector-shift-left.c @@ -3,11 +3,6 @@ #include <arm_neon.h> // REQUIRES: aarch64-registered-target -// Widening left-shifts should have a range of 0..(sizeinbits(arg)-1), this range has had -// to be weakened to 0..((sizeinbits(arg)*2)-1) due to a use of vshll_n_s16 with an -// out-of-bounds immediate in the defintiion of vcvt_f32_bf16. As a result, the upper bounds -// of widening left-shift intrinsics are not currently tested here. - void test_vector_shift_left_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16) { vshl_n_s8(arg_i8x8, 0); vshl_n_s8(arg_i8x8, 7); @@ -18,7 +13,6 @@ void test_vector_shift_left_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16) { vshlq_n_s8(arg_i8x16, 7); vshlq_n_s8(arg_i8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_s8(arg_i8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_s16(int16x4_t arg_i16x4, int16x8_t arg_i16x8) { @@ -31,7 +25,6 @@ void test_vector_shift_left_s16(int16x4_t arg_i16x4, int16x8_t arg_i16x8) { vshlq_n_s16(arg_i16x8, 15); vshlq_n_s16(arg_i16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_s16(arg_i16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_s32(int32x2_t arg_i32x2, int32x4_t arg_i32x4) { @@ -44,7 +37,6 @@ void test_vector_shift_left_s32(int32x2_t arg_i32x2, int32x4_t arg_i32x4) { vshlq_n_s32(arg_i32x4, 31); vshlq_n_s32(arg_i32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_s32(arg_i32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_s64(int64_t arg_i64, int64x2_t arg_i64x2, int64x1_t arg_i64x1) { @@ -62,7 +54,6 @@ void test_vector_shift_left_s64(int64_t arg_i64, int64x2_t arg_i64x2, int64x1_t vshld_n_s64(arg_i64, 63); vshld_n_s64(arg_i64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshld_n_s64(arg_i64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_u8(uint8x8_t arg_u8x8, uint8x16_t arg_u8x16) { @@ -75,7 +66,6 @@ void test_vector_shift_left_u8(uint8x8_t arg_u8x8, uint8x16_t arg_u8x16) { vshlq_n_u8(arg_u8x16, 7); vshlq_n_u8(arg_u8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_u8(arg_u8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_u16(uint16x4_t arg_u16x4, uint16x8_t arg_u16x8) { @@ -88,7 +78,6 @@ void test_vector_shift_left_u16(uint16x4_t arg_u16x4, uint16x8_t arg_u16x8) { vshlq_n_u16(arg_u16x8, 15); vshlq_n_u16(arg_u16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_u16(arg_u16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_u32(uint32x2_t arg_u32x2, uint32x4_t arg_u32x4) { @@ -101,7 +90,6 @@ void test_vector_shift_left_u32(uint32x2_t arg_u32x2, uint32x4_t arg_u32x4) { vshlq_n_u32(arg_u32x4, 31); vshlq_n_u32(arg_u32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshlq_n_u32(arg_u32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_u64(uint64x1_t arg_u64x1, uint64_t arg_u64, uint64x2_t arg_u64x2) { @@ -119,7 +107,6 @@ void test_vector_shift_left_u64(uint64x1_t arg_u64x1, uint64_t arg_u64, uint64x2 vshld_n_u64(arg_u64, 63); vshld_n_u64(arg_u64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshld_n_u64(arg_u64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16, int8_t arg_i8) { @@ -152,7 +139,6 @@ void test_vector_saturating_shift_left_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16 vqshlub_n_s8(arg_i8, 7); vqshlub_n_s8(arg_i8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshlub_n_s8(arg_i8, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_s16(int16x4_t arg_i16x4, int16_t arg_i16, int16x8_t arg_i16x8) { @@ -185,7 +171,6 @@ void test_vector_saturating_shift_left_s16(int16x4_t arg_i16x4, int16_t arg_i16, vqshluh_n_s16(arg_i16, 15); vqshluh_n_s16(arg_i16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshluh_n_s16(arg_i16, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_s32(int32x2_t arg_i32x2, int32_t arg_i32, int32x4_t arg_i32x4) { @@ -218,7 +203,6 @@ void test_vector_saturating_shift_left_s32(int32x2_t arg_i32x2, int32_t arg_i32, vqshlus_n_s32(arg_i32, 31); vqshlus_n_s32(arg_i32, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshlus_n_s32(arg_i32, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_s64(int64_t arg_i64, int64x2_t arg_i64x2, int64x1_t arg_i64x1) { @@ -251,7 +235,6 @@ void test_vector_saturating_shift_left_s64(int64_t arg_i64, int64x2_t arg_i64x2, vqshlud_n_s64(arg_i64, 63); vqshlud_n_s64(arg_i64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshlud_n_s64(arg_i64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_u8(uint8x8_t arg_u8x8, uint8_t arg_u8, uint8x16_t arg_u8x16) { @@ -269,7 +252,6 @@ void test_vector_saturating_shift_left_u8(uint8x8_t arg_u8x8, uint8_t arg_u8, ui vqshlb_n_u8(arg_u8, 7); vqshlb_n_u8(arg_u8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshlb_n_u8(arg_u8, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_u16(uint16_t arg_u16, uint16x4_t arg_u16x4, uint16x8_t arg_u16x8) { @@ -287,7 +269,6 @@ void test_vector_saturating_shift_left_u16(uint16_t arg_u16, uint16x4_t arg_u16x vqshlh_n_u16(arg_u16, 15); vqshlh_n_u16(arg_u16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshlh_n_u16(arg_u16, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_u32(uint32x2_t arg_u32x2, uint32x4_t arg_u32x4, uint32_t arg_u32) { @@ -305,7 +286,6 @@ void test_vector_saturating_shift_left_u32(uint32x2_t arg_u32x2, uint32x4_t arg_ vqshls_n_u32(arg_u32, 31); vqshls_n_u32(arg_u32, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshls_n_u32(arg_u32, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_saturating_shift_left_u64(uint64x1_t arg_u64x1, uint64_t arg_u64, uint64x2_t arg_u64x2) { @@ -323,68 +303,78 @@ void test_vector_saturating_shift_left_u64(uint64x1_t arg_u64x1, uint64_t arg_u6 vqshld_n_u64(arg_u64, 63); vqshld_n_u64(arg_u64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vqshld_n_u64(arg_u64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_widen_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16) { vshll_n_s8(arg_i8x8, 0); vshll_n_s8(arg_i8x8, 7); vshll_n_s8(arg_i8x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} - + vshll_n_s8(arg_i8x8, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_s8(arg_i8x16, 0); vshll_high_n_s8(arg_i8x16, 7); vshll_high_n_s8(arg_i8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_s8(arg_i8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_widen_s16(int16x4_t arg_i16x4, int16x8_t arg_i16x8) { vshll_n_s16(arg_i16x4, 0); vshll_n_s16(arg_i16x4, 15); vshll_n_s16(arg_i16x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_n_s16(arg_i16x4, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_s16(arg_i16x8, 0); vshll_high_n_s16(arg_i16x8, 15); vshll_high_n_s16(arg_i16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_s16(arg_i16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_widen_s32(int32x2_t arg_i32x2, int32x4_t arg_i32x4) { vshll_n_s32(arg_i32x2, 0); vshll_n_s32(arg_i32x2, 31); vshll_n_s32(arg_i32x2, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_n_s32(arg_i32x2, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_s32(arg_i32x4, 0); vshll_high_n_s32(arg_i32x4, 31); vshll_high_n_s32(arg_i32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_s32(arg_i32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_widen_u8(uint8x8_t arg_u8x8, uint8x16_t arg_u8x16) { vshll_n_u8(arg_u8x8, 0); vshll_n_u8(arg_u8x8, 7); vshll_n_u8(arg_u8x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_n_u8(arg_u8x8, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_u8(arg_u8x16, 0); vshll_high_n_u8(arg_u8x16, 7); vshll_high_n_u8(arg_u8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_u8(arg_u8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_widen_u16(uint16x4_t arg_u16x4, uint16x8_t arg_u16x8) { vshll_n_u16(arg_u16x4, 0); vshll_n_u16(arg_u16x4, 15); vshll_n_u16(arg_u16x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_n_u16(arg_u16x4, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_u16(arg_u16x8, 0); vshll_high_n_u16(arg_u16x8, 15); vshll_high_n_u16(arg_u16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_u16(arg_u16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_widen_u32(uint32x2_t arg_u32x2, uint32x4_t arg_u32x4) { vshll_n_u32(arg_u32x2, 0); vshll_n_u32(arg_u32x2, 31); vshll_n_u32(arg_u32x2, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_n_u32(arg_u32x2, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} vshll_high_n_u32(arg_u32x4, 0); vshll_high_n_u32(arg_u32x4, 31); vshll_high_n_u32(arg_u32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} + vshll_high_n_u32(arg_u32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} } void test_vector_shift_left_and_insert_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16) { @@ -397,7 +387,6 @@ void test_vector_shift_left_and_insert_s8(int8x8_t arg_i8x8, int8x16_t arg_i8x16 vsliq_n_s8(arg_i8x16, arg_i8x16, 7); vsliq_n_s8(arg_i8x16, arg_i8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_s8(arg_i8x16, arg_i8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_s16(int16x4_t arg_i16x4, int16x8_t arg_i16x8) { @@ -410,7 +399,6 @@ void test_vector_shift_left_and_insert_s16(int16x4_t arg_i16x4, int16x8_t arg_i1 vsliq_n_s16(arg_i16x8, arg_i16x8, 15); vsliq_n_s16(arg_i16x8, arg_i16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_s16(arg_i16x8, arg_i16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_s32(int32x2_t arg_i32x2, int32x4_t arg_i32x4) { @@ -423,7 +411,6 @@ void test_vector_shift_left_and_insert_s32(int32x2_t arg_i32x2, int32x4_t arg_i3 vsliq_n_s32(arg_i32x4, arg_i32x4, 31); vsliq_n_s32(arg_i32x4, arg_i32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_s32(arg_i32x4, arg_i32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_s64(int64_t arg_i64, int64x2_t arg_i64x2, int64x1_t arg_i64x1) { @@ -441,7 +428,6 @@ void test_vector_shift_left_and_insert_s64(int64_t arg_i64, int64x2_t arg_i64x2, vslid_n_s64(arg_i64, arg_i64, 63); vslid_n_s64(arg_i64, arg_i64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vslid_n_s64(arg_i64, arg_i64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_u8(uint8x8_t arg_u8x8, uint8x16_t arg_u8x16) { @@ -454,7 +440,6 @@ void test_vector_shift_left_and_insert_u8(uint8x8_t arg_u8x8, uint8x16_t arg_u8x vsliq_n_u8(arg_u8x16, arg_u8x16, 7); vsliq_n_u8(arg_u8x16, arg_u8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_u8(arg_u8x16, arg_u8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_u16(uint16x4_t arg_u16x4, uint16x8_t arg_u16x8) { @@ -467,7 +452,6 @@ void test_vector_shift_left_and_insert_u16(uint16x4_t arg_u16x4, uint16x8_t arg_ vsliq_n_u16(arg_u16x8, arg_u16x8, 15); vsliq_n_u16(arg_u16x8, arg_u16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_u16(arg_u16x8, arg_u16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_u32(uint32x2_t arg_u32x2, uint32x4_t arg_u32x4) { @@ -480,7 +464,6 @@ void test_vector_shift_left_and_insert_u32(uint32x2_t arg_u32x2, uint32x4_t arg_ vsliq_n_u32(arg_u32x4, arg_u32x4, 31); vsliq_n_u32(arg_u32x4, arg_u32x4, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_u32(arg_u32x4, arg_u32x4, 32); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_u64(uint64x1_t arg_u64x1, uint64_t arg_u64, uint64x2_t arg_u64x2) { @@ -498,7 +481,6 @@ void test_vector_shift_left_and_insert_u64(uint64x1_t arg_u64x1, uint64_t arg_u6 vslid_n_u64(arg_u64, arg_u64, 63); vslid_n_u64(arg_u64, arg_u64, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vslid_n_u64(arg_u64, arg_u64, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_p64(poly64x2_t arg_p64x2, poly64x1_t arg_p64x1) { @@ -511,7 +493,6 @@ void test_vector_shift_left_and_insert_p64(poly64x2_t arg_p64x2, poly64x1_t arg_ vsliq_n_p64(arg_p64x2, arg_p64x2, 63); vsliq_n_p64(arg_p64x2, arg_p64x2, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_p64(arg_p64x2, arg_p64x2, 64); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_p8(poly8x16_t arg_p8x16, poly8x8_t arg_p8x8) { @@ -524,7 +505,6 @@ void test_vector_shift_left_and_insert_p8(poly8x16_t arg_p8x16, poly8x8_t arg_p8 vsliq_n_p8(arg_p8x16, arg_p8x16, 7); vsliq_n_p8(arg_p8x16, arg_p8x16, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_p8(arg_p8x16, arg_p8x16, 8); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } void test_vector_shift_left_and_insert_p16(poly16x4_t arg_p16x4, poly16x8_t arg_p16x8) { @@ -537,6 +517,5 @@ void test_vector_shift_left_and_insert_p16(poly16x4_t arg_p16x4, poly16x8_t arg_ vsliq_n_p16(arg_p16x8, arg_p16x8, 15); vsliq_n_p16(arg_p16x8, arg_p16x8, -1); // expected-error-re {{argument value {{.*}} is outside the valid range}} vsliq_n_p16(arg_p16x8, arg_p16x8, 16); // expected-error-re {{argument value {{.*}} is outside the valid range}} - } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index a660a3f11bdb2..ca221d49c55d7 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -9541,6 +9541,11 @@ def : Pat<(v4i32 (concat_vectors (v2i32 V64:$Rd), (SHRNv4i32_shift (INSERT_SUBREG (IMPLICIT_DEF), V64:$Rd, dsub), V128:$Rn, vecshiftR32Narrow:$imm)>; +def : Pat<(shl (v4i32 (zext (v4i16 (extract_high_v8i16 (v8i16 V128:$Rm))))), (v4i32 (AArch64dup (i32 16)))), + (SHLLv8i16 V128:$Rm)>; +def : Pat<(shl (v4i32 (zext (v4i16 V64:$Rm))), (v4i32 (AArch64dup (i32 16)))), + (SHLLv4i16 V64:$Rm)>; + def : Pat<(shl (v8i16 (zext (v8i8 V64:$Rm))), (v8i16 (AArch64dup (i32 imm32_0_7:$size)))), (USHLLv8i8_shift V64:$Rm, (i32 imm32_0_7:$size))>; def : Pat<(shl (v4i32 (zext (v4i16 V64:$Rm))), (v4i32 (AArch64dup (i32 imm32_0_15:$size)))), diff --git a/llvm/test/CodeGen/AArch64/arm64-vcvt_f.ll b/llvm/test/CodeGen/AArch64/arm64-vcvt_f.ll index 43137f4b97feb..4bafeea3bc363 100644 --- a/llvm/test/CodeGen/AArch64/arm64-vcvt_f.ll +++ b/llvm/test/CodeGen/AArch64/arm64-vcvt_f.ll @@ -186,6 +186,60 @@ define <2 x bfloat> @test_vcvt_bf16_f64(<2 x double> %v) nounwind readnone ssp { ret <2 x bfloat> %vcvt1.i } +define dso_local <4 x float> @test_vcvt_f32_bf16(<4 x bfloat> noundef %a) local_unnamed_addr #0 { +; CHECK-LABEL: test_vcvt_f32_bf16: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: shll.4s v0, v0, #16 +; CHECK-NEXT: ret +entry: + %0 = bitcast <4 x bfloat> %a to <4 x i16> + %vmovl.i = zext <4 x i16> %0 to <4 x i32> + %vshl_n.i = shl nuw <4 x i32> %vmovl.i, splat (i32 16) + %1 = bitcast <4 x i32> %vshl_n.i to <4 x float> + ret <4 x float> %1 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable +define dso_local <4 x float> @test_vcvtq_low_f32_bf16(<8 x bfloat> noundef %a) local_unnamed_addr #0 { +; CHECK-SD-LABEL: test_vcvtq_low_f32_bf16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: shll.4s v0, v0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-FI-LABEL: test_vcvtq_low_f32_bf16: +; CHECK-FI: // %bb.0: // %entry +; CHECK-FI-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-FI-NEXT: shll.4s v0, v0, #16 +; CHECK-FI-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvtq_low_f32_bf16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: shll.4s v0, v0, #16 +; CHECK-GI-NEXT: ret +entry: + %0 = bitcast <8 x bfloat> %a to <8 x i16> + %1 = shufflevector <8 x i16> %0, <8 x i16> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + %vmovl.i = zext <4 x i16> %1 to <4 x i32> + %vshl_n.i.i = shl nuw <4 x i32> %vmovl.i, splat (i32 16) + %2 = bitcast <4 x i32> %vshl_n.i.i to <4 x float> + ret <4 x float> %2 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable +define dso_local <4 x float> @test_vcvtq_high_f32_bf16(<8 x bfloat> noundef %a) local_unnamed_addr #0 { +; CHECK-LABEL: test_vcvtq_high_f32_bf16: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: shll2.4s v0, v0, #16 +; CHECK-NEXT: ret +entry: + %0 = bitcast <8 x bfloat> %a to <8 x i16> + %1 = shufflevector <8 x i16> %0, <8 x i16> poison, <4 x i32> <i32 4, i32 5, i32 6, i32 7> + %vmovl.i = zext <4 x i16> %1 to <4 x i32> + %vshl_n.i.i = shl nuw <4 x i32> %vmovl.i, splat (i32 16) + %2 = bitcast <4 x i32> %vshl_n.i.i to <4 x float> + ret <4 x float> %2 +} + define half @test_vcvt_f16_f32(<1 x float> %x) { ; CHECK-SD-LABEL: test_vcvt_f16_f32: ; CHECK-SD: // %bb.0: diff --git a/llvm/test/CodeGen/AArch64/arm64-vshift.ll b/llvm/test/CodeGen/AArch64/arm64-vshift.ll index 8d17836a2b761..ee500710c1a97 100644 --- a/llvm/test/CodeGen/AArch64/arm64-vshift.ll +++ b/llvm/test/CodeGen/AArch64/arm64-vshift.ll @@ -4135,16 +4135,10 @@ define <8 x i16> @shll(<8 x i8> %in) { } define <4 x i32> @shll_high(<8 x i16> %in) { -; CHECK-SD-LABEL: shll_high: -; CHECK-SD: // %bb.0: -; CHECK-SD-NEXT: shll2 v0.4s, v0.8h, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: shll_high: -; CHECK-GI: // %bb.0: -; CHECK-GI-NEXT: ushll2 v0.4s, v0.8h, #0 -; CHECK-GI-NEXT: shl v0.4s, v0.4s, #16 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: shll_high: +; CHECK: // %bb.0: +; CHECK-NEXT: shll2 v0.4s, v0.8h, #16 +; CHECK-NEXT: ret %extract = shufflevector <8 x i16> %in, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7> %ext = zext <4 x i16> %extract to <4 x i32> %res = shl <4 x i32> %ext, <i32 16, i32 16, i32 16, i32 16> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
