diff --git a/clang/include/clang/Basic/arm_mve.td b/clang/include/clang/Basic/arm_mve.td --- a/clang/include/clang/Basic/arm_mve.td +++ b/clang/include/clang/Basic/arm_mve.td @@ -1180,6 +1180,13 @@ defm vrmlsldavh : MVEBinaryVectorHoriz64R; } +let params = T.All8 in +def vrev16q : Intrinsic; +let params = !listconcat(T.All8, T.All16) in +def vrev32q : Intrinsic; +let params = T.Usual in +def vrev64q : Intrinsic; + foreach desttype = T.All in { // We want a vreinterpretq between every pair of supported vector types // _except_ that there shouldn't be one from a type to itself. diff --git a/clang/include/clang/Basic/arm_mve_defs.td b/clang/include/clang/Basic/arm_mve_defs.td --- a/clang/include/clang/Basic/arm_mve_defs.td +++ b/clang/include/clang/Basic/arm_mve_defs.td @@ -125,6 +125,9 @@ def uitofp: IRBuilder<"CreateUIToFP">; def fptosi: IRBuilder<"CreateFPToSI">; def fptoui: IRBuilder<"CreateFPToUI">; +def vrev: CGHelperFn<"ARMMVEVectorElementReverse"> { + let special_params = [IRBuilderIntParam<1, "unsigned">]; +} // A node that makes an Address out of a pointer-typed Value, by // providing an alignment as the second argument. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7069,6 +7069,21 @@ return ARMMVEVectorSplat(Builder, Lane); } +static llvm::Value *ARMMVEVectorElementReverse(CGBuilderTy &Builder, + llvm::Value *V, + unsigned ReverseWidth) { + // MVE-specific helper function which reverses the elements of a + // vector within every (ReverseWidth)-bit collection of lanes. + SmallVector Indices; + unsigned LaneSize = V->getType()->getScalarSizeInBits(); + unsigned Elements = 128 / LaneSize; + unsigned Mask = ReverseWidth / LaneSize - 1; + for (unsigned i = 0; i < Elements; i++) + Indices.push_back(i ^ Mask); + return Builder.CreateShuffleVector(V, llvm::UndefValue::get(V->getType()), + Indices); +} + Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue, diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vrev.c b/clang/test/CodeGen/arm-mve-intrinsics/vrev.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-mve-intrinsics/vrev.c @@ -0,0 +1,215 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple thumbv8.1m.main-arm-none-eabi -target-feature +mve.fp -mfloat-abi hard -fallow-half-arguments-and-returns -O0 -disable-O0-optnone -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s +// RUN: %clang_cc1 -triple thumbv8.1m.main-arm-none-eabi -target-feature +mve.fp -mfloat-abi hard -fallow-half-arguments-and-returns -O0 -disable-O0-optnone -DPOLYMORPHIC -S -emit-llvm -o - %s | opt -S -mem2reg -sroa -early-cse | FileCheck %s + +#include + +// CHECK-LABEL: @test_vrev16q_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_vrev16q_s8(int8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev16q(a); +#else /* POLYMORPHIC */ + return vrev16q_s8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev16q_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_vrev16q_u8(uint8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev16q(a); +#else /* POLYMORPHIC */ + return vrev16q_u8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev32q_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_vrev32q_s8(int8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev32q(a); +#else /* POLYMORPHIC */ + return vrev32q_s8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev32q_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_vrev32q_u8(uint8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev32q(a); +#else /* POLYMORPHIC */ + return vrev32q_u8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev32q_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x i16> [[A:%.*]], <8 x i16> undef, <8 x i32> +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +int16x8_t test_vrev32q_s16(int16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev32q(a); +#else /* POLYMORPHIC */ + return vrev32q_s16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev32q_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x i16> [[A:%.*]], <8 x i16> undef, <8 x i32> +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +uint16x8_t test_vrev32q_u16(uint16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev32q(a); +#else /* POLYMORPHIC */ + return vrev32q_u16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev32q_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x half> [[A:%.*]], <8 x half> undef, <8 x i32> +// CHECK-NEXT: ret <8 x half> [[TMP0]] +// +float16x8_t test_vrev32q_f16(float16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev32q(a); +#else /* POLYMORPHIC */ + return vrev32q_f16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_vrev64q_s8(int8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_s8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i8> [[A:%.*]], <16 x i8> undef, <16 x i32> +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_vrev64q_u8(uint8x16_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_u8(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x i16> [[A:%.*]], <8 x i16> undef, <8 x i32> +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +int16x8_t test_vrev64q_s16(int16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_s16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x i16> [[A:%.*]], <8 x i16> undef, <8 x i32> +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +uint16x8_t test_vrev64q_u16(uint16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_u16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <8 x half> [[A:%.*]], <8 x half> undef, <8 x i32> +// CHECK-NEXT: ret <8 x half> [[TMP0]] +// +float16x8_t test_vrev64q_f16(float16x8_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_f16(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <4 x float> [[A:%.*]], <4 x float> undef, <4 x i32> +// CHECK-NEXT: ret <4 x float> [[TMP0]] +// +float32x4_t test_vrev64q_f32(float32x4_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_f32(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> undef, <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +int32x4_t test_vrev64q_s32(int32x4_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_s32(a); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vrev64q_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> undef, <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +uint32x4_t test_vrev64q_u32(uint32x4_t a) +{ +#ifdef POLYMORPHIC + return vrev64q(a); +#else /* POLYMORPHIC */ + return vrev64q_u32(a); +#endif /* POLYMORPHIC */ +}