[clang] [llvm] [Clang][ARM] Fix immediate range for NEON widening left-shifts (PR #212459)
Kieran B via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 28 03:58:54 PDT 2026
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 <kieran.bailey at arm.com>
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>
More information about the cfe-commits
mailing list