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 @@ -413,4 +413,9 @@ def vuninitializedq_polymorphic: Intrinsic< Vector, (args Vector), (undef Vector)>; } + + def vgetq_lane: Intrinsic; + def vsetq_lane: Intrinsic:$e, Vector:$v, imm_lane:$lane), + (ielt_var $v, $e, $lane)>; } 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 @@ -77,6 +77,8 @@ def ielt_const: IRBuilder<"CreateInsertElement"> { let special_params = [IRBuilderIntParam<2, "uint64_t">]; } +def ielt_var: IRBuilder<"CreateInsertElement">; +def xelt_var: IRBuilder<"CreateExtractElement">; def trunc: IRBuilder<"CreateTrunc">; def bitcast: IRBuilder<"CreateBitCast">; def extend: CGHelperFn<"SignOrZeroExtend"> { @@ -172,6 +174,10 @@ // of _s32 / _f16 / _u8 suffix. def Void : Type; +// A wrapper you can put on an intrinsic's argument type to prevent it from +// being automatically promoted to i32 from a smaller integer type. +class unpromoted : Type { Type underlying_type = t; } + // Primitive types: base class, and an instance for the set of scalar integer // and floating types that MVE uses. class PrimitiveType: Type { @@ -285,7 +291,7 @@ // imm_lane has to be the index of a vector lane in the main vector type, i.e // it can range from 0 to (128 / size of scalar)-1 inclusive. (e.g. vgetq_lane) -def imm_lane : Immediate; +def imm_lane : Immediate; // imm_1to32 can be in the range 1 to 32, unconditionally. (e.g. scalar shift // intrinsics) diff --git a/clang/test/CodeGen/arm-mve-intrinsics/get-set-lane.c b/clang/test/CodeGen/arm-mve-intrinsics/get-set-lane.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-mve-intrinsics/get-set-lane.c @@ -0,0 +1,291 @@ +// 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 -sroa -early-cse | 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_vgetq_lane_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <8 x half> [[A:%.*]], i32 2 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast half [[TMP0]] to i16 +// CHECK-NEXT: [[TMP_0_INSERT_EXT:%.*]] = zext i16 [[TMP1]] to i32 +// CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP_0_INSERT_EXT]] to float +// CHECK-NEXT: ret float [[TMP2]] +// +float16_t test_vgetq_lane_f16(float16x8_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 2); +#else /* POLYMORPHIC */ + return vgetq_lane_f16(a, 2); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x float> [[A:%.*]], i32 3 +// CHECK-NEXT: ret float [[TMP0]] +// +float32_t test_vgetq_lane_f32(float32x4_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 3); +#else /* POLYMORPHIC */ + return vgetq_lane_f32(a, 3); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <8 x i16> [[A:%.*]], i32 4 +// CHECK-NEXT: ret i16 [[TMP0]] +// +int16_t test_vgetq_lane_s16(int16x8_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 4); +#else /* POLYMORPHIC */ + return vgetq_lane_s16(a, 4); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x i32> [[A:%.*]], i32 0 +// CHECK-NEXT: ret i32 [[TMP0]] +// +int32_t test_vgetq_lane_s32(int32x4_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 0); +#else /* POLYMORPHIC */ + return vgetq_lane_s32(a, 0); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x i64> [[A:%.*]], i32 0 +// CHECK-NEXT: ret i64 [[TMP0]] +// +int64_t test_vgetq_lane_s64(int64x2_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 0); +#else /* POLYMORPHIC */ + return vgetq_lane_s64(a, 0); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <16 x i8> [[A:%.*]], i32 10 +// CHECK-NEXT: ret i8 [[TMP0]] +// +int8_t test_vgetq_lane_s8(int8x16_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 10); +#else /* POLYMORPHIC */ + return vgetq_lane_s8(a, 10); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <8 x i16> [[A:%.*]], i32 3 +// CHECK-NEXT: ret i16 [[TMP0]] +// +uint16_t test_vgetq_lane_u16(uint16x8_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 3); +#else /* POLYMORPHIC */ + return vgetq_lane_u16(a, 3); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x i32> [[A:%.*]], i32 3 +// CHECK-NEXT: ret i32 [[TMP0]] +// +uint32_t test_vgetq_lane_u32(uint32x4_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 3); +#else /* POLYMORPHIC */ + return vgetq_lane_u32(a, 3); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x i64> [[A:%.*]], i32 1 +// CHECK-NEXT: ret i64 [[TMP0]] +// +uint64_t test_vgetq_lane_u64(uint64x2_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 1); +#else /* POLYMORPHIC */ + return vgetq_lane_u64(a, 1); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vgetq_lane_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <16 x i8> [[A:%.*]], i32 1 +// CHECK-NEXT: ret i8 [[TMP0]] +// +uint8_t test_vgetq_lane_u8(uint8x16_t a) +{ +#ifdef POLYMORPHIC + return vgetq_lane(a, 1); +#else /* POLYMORPHIC */ + return vgetq_lane_u8(a, 1); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast float [[A_COERCE:%.*]] to i32 +// CHECK-NEXT: [[TMP_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[TMP0]] to i16 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast i16 [[TMP_0_EXTRACT_TRUNC]] to half +// CHECK-NEXT: [[TMP2:%.*]] = insertelement <8 x half> [[B:%.*]], half [[TMP1]], i32 4 +// CHECK-NEXT: ret <8 x half> [[TMP2]] +// +float16x8_t test_vsetq_lane_f16(float16_t a, float16x8_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 4); +#else /* POLYMORPHIC */ + return vsetq_lane_f16(a, b, 4); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x float> [[B:%.*]], float [[A:%.*]], i32 2 +// CHECK-NEXT: ret <4 x float> [[TMP0]] +// +float32x4_t test_vsetq_lane_f32(float32_t a, float32x4_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 2); +#else /* POLYMORPHIC */ + return vsetq_lane_f32(a, b, 2); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <16 x i8> [[B:%.*]], i8 [[A:%.*]], i32 12 +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_vsetq_lane_s8(int8_t a, int8x16_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 12); +#else /* POLYMORPHIC */ + return vsetq_lane_s8(a, b, 12); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> [[B:%.*]], i16 [[A:%.*]], i32 6 +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +int16x8_t test_vsetq_lane_s16(int16_t a, int16x8_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 6); +#else /* POLYMORPHIC */ + return vsetq_lane_s16(a, b, 6); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> [[B:%.*]], i32 [[A:%.*]], i32 2 +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +int32x4_t test_vsetq_lane_s32(int32_t a, int32x4_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 2); +#else /* POLYMORPHIC */ + return vsetq_lane_s32(a, b, 2); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i64> [[B:%.*]], i64 [[A:%.*]], i32 0 +// CHECK-NEXT: ret <2 x i64> [[TMP0]] +// +int64x2_t test_vsetq_lane_s64(int64_t a, int64x2_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 0); +#else /* POLYMORPHIC */ + return vsetq_lane_s64(a, b, 0); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <16 x i8> [[B:%.*]], i8 [[A:%.*]], i32 2 +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_vsetq_lane_u8(uint8_t a, uint8x16_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 2); +#else /* POLYMORPHIC */ + return vsetq_lane_u8(a, b, 2); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i16> [[B:%.*]], i16 [[A:%.*]], i32 7 +// CHECK-NEXT: ret <8 x i16> [[TMP0]] +// +uint16x8_t test_vsetq_lane_u16(uint16_t a, uint16x8_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 7); +#else /* POLYMORPHIC */ + return vsetq_lane_u16(a, b, 7); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> [[B:%.*]], i32 [[A:%.*]], i32 0 +// CHECK-NEXT: ret <4 x i32> [[TMP0]] +// +uint32x4_t test_vsetq_lane_u32(uint32_t a, uint32x4_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 0); +#else /* POLYMORPHIC */ + return vsetq_lane_u32(a, b, 0); +#endif /* POLYMORPHIC */ +} + +// CHECK-LABEL: @test_vsetq_lane_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i64> [[B:%.*]], i64 [[A:%.*]], i32 1 +// CHECK-NEXT: ret <2 x i64> [[TMP0]] +// +uint64x2_t test_vsetq_lane_u64(uint64_t a, uint64x2_t b) +{ +#ifdef POLYMORPHIC + return vsetq_lane(a, b, 1); +#else /* POLYMORPHIC */ + return vsetq_lane_u64(a, b, 1); +#endif /* POLYMORPHIC */ +} diff --git a/clang/test/CodeGen/arm-mve-intrinsics/load-store.c b/clang/test/CodeGen/arm-mve-intrinsics/load-store.c --- a/clang/test/CodeGen/arm-mve-intrinsics/load-store.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/load-store.c @@ -1,6 +1,6 @@ // 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 -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 -O0 -disable-O0-optnone -DPOLYMORPHIC -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 -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 | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/scalar-shifts.c b/clang/test/CodeGen/arm-mve-intrinsics/scalar-shifts.c --- a/clang/test/CodeGen/arm-mve-intrinsics/scalar-shifts.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/scalar-shifts.c @@ -1,5 +1,5 @@ // 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 -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 -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c b/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c --- a/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c @@ -1,6 +1,6 @@ // 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 -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 -O0 -disable-O0-optnone -DPOLYMORPHIC -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 -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 | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vadc.c b/clang/test/CodeGen/arm-mve-intrinsics/vadc.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vadc.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vadc.c @@ -1,6 +1,6 @@ // 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 -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 -O0 -disable-O0-optnone -DPOLYMORPHIC -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 -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 | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vaddq.c b/clang/test/CodeGen/arm-mve-intrinsics/vaddq.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vaddq.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vaddq.c @@ -1,6 +1,6 @@ // 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 -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 -O0 -disable-O0-optnone -DPOLYMORPHIC -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 -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 | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vcvt.c b/clang/test/CodeGen/arm-mve-intrinsics/vcvt.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vcvt.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vcvt.c @@ -1,5 +1,5 @@ // 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 -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 -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vld24.c b/clang/test/CodeGen/arm-mve-intrinsics/vld24.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vld24.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vld24.c @@ -1,6 +1,6 @@ // 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 -O0 -disable-O0-optnone -S -emit-llvm -o - %s | opt -S -mem2reg -sroa -early-cse | FileCheck %s -// RUN: %clang_cc1 -triple thumbv8.1m.main-arm-none-eabi -target-feature +mve.fp -mfloat-abi hard -O0 -disable-O0-optnone -DPOLYMORPHIC -S -emit-llvm -o - %s | opt -S -mem2reg -sroa -early-cse | 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 -S -emit-llvm -o - %s | opt -S -mem2reg -sroa -early-cse | 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 diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vldr.c b/clang/test/CodeGen/arm-mve-intrinsics/vldr.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vldr.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vldr.c @@ -1,5 +1,5 @@ // 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 -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 -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s #include diff --git a/clang/test/CodeGen/arm-mve-intrinsics/vminvq.c b/clang/test/CodeGen/arm-mve-intrinsics/vminvq.c --- a/clang/test/CodeGen/arm-mve-intrinsics/vminvq.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/vminvq.c @@ -1,6 +1,6 @@ // 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 -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 -O0 -disable-O0-optnone -DPOLYMORPHIC -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 -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 | FileCheck %s #include diff --git a/clang/test/Sema/arm-mve-immediates.c b/clang/test/Sema/arm-mve-immediates.c --- a/clang/test/Sema/arm-mve-immediates.c +++ b/clang/test/Sema/arm-mve-immediates.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple thumbv8.1m.main-arm-none-eabi -target-feature +mve.fp -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple thumbv8.1m.main-arm-none-eabi -fallow-half-arguments-and-returns -target-feature +mve.fp -verify -fsyntax-only %s #include @@ -54,3 +54,47 @@ vstrwq_scatter_base(addr32, 2, addr32); // expected-error {{argument should be a multiple of 4}} vstrwq_scatter_base(addr32, 1, addr32); // expected-error {{argument should be a multiple of 4}} } + +void test_lane_indices(uint8x16_t v16, uint16x8_t v8, + uint32x4_t v4, uint64x2_t v2) +{ + vgetq_lane_u8(v16, -1); // expected-error {{argument value -1 is outside the valid range [0, 15]}} + vgetq_lane_u8(v16, 0); + vgetq_lane_u8(v16, 15); + vgetq_lane_u8(v16, 16); // expected-error {{argument value 16 is outside the valid range [0, 15]}} + + vgetq_lane_u16(v8, -1); // expected-error {{argument value -1 is outside the valid range [0, 7]}} + vgetq_lane_u16(v8, 0); + vgetq_lane_u16(v8, 7); + vgetq_lane_u16(v8, 8); // expected-error {{argument value 8 is outside the valid range [0, 7]}} + + vgetq_lane_u32(v4, -1); // expected-error {{argument value -1 is outside the valid range [0, 3]}} + vgetq_lane_u32(v4, 0); + vgetq_lane_u32(v4, 3); + vgetq_lane_u32(v4, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}} + + vgetq_lane_u64(v2, -1); // expected-error {{argument value -1 is outside the valid range [0, 1]}} + vgetq_lane_u64(v2, 0); + vgetq_lane_u64(v2, 1); + vgetq_lane_u64(v2, 2); // expected-error {{argument value 2 is outside the valid range [0, 1]}} + + vsetq_lane_u8(23, v16, -1); // expected-error {{argument value -1 is outside the valid range [0, 15]}} + vsetq_lane_u8(23, v16, 0); + vsetq_lane_u8(23, v16, 15); + vsetq_lane_u8(23, v16, 16); // expected-error {{argument value 16 is outside the valid range [0, 15]}} + + vsetq_lane_u16(23, v8, -1); // expected-error {{argument value -1 is outside the valid range [0, 7]}} + vsetq_lane_u16(23, v8, 0); + vsetq_lane_u16(23, v8, 7); + vsetq_lane_u16(23, v8, 8); // expected-error {{argument value 8 is outside the valid range [0, 7]}} + + vsetq_lane_u32(23, v4, -1); // expected-error {{argument value -1 is outside the valid range [0, 3]}} + vsetq_lane_u32(23, v4, 0); + vsetq_lane_u32(23, v4, 3); + vsetq_lane_u32(23, v4, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}} + + vsetq_lane_u64(23, v2, -1); // expected-error {{argument value -1 is outside the valid range [0, 1]}} + vsetq_lane_u64(23, v2, 0); + vsetq_lane_u64(23, v2, 1); + vsetq_lane_u64(23, v2, 2); // expected-error {{argument value 2 is outside the valid range [0, 1]}} +} diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -980,7 +980,8 @@ const Type *Param); Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum, const Result::Scope &Scope, const Type *Param); - Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType); + Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, + bool Promote); // Constructor and top-level functions. @@ -1003,8 +1004,13 @@ } const Type *MveEmitter::getType(Record *R, const Type *Param) { + // Pass to a subfield of any wrapper records. We don't expect more than one + // of these: immediate operands are used as plain numbers rather than as + // llvm::Value, so it's meaningless to promote their type anyway. if (R->isSubClassOf("Immediate")) - R = R->getValueAsDef("type"); // pass to subfield + R = R->getValueAsDef("type"); + else if (R->isSubClassOf("unpromoted")) + R = R->getValueAsDef("underlying_type"); if (R->getName() == "Void") return getVoidType(); @@ -1197,12 +1203,13 @@ PrintFatalError("bad dag argument type for code generation"); } -Result::Ptr MveEmitter::getCodeForArg(unsigned ArgNum, const Type *ArgType) { +Result::Ptr MveEmitter::getCodeForArg(unsigned ArgNum, const Type *ArgType, + bool Promote) { Result::Ptr V = std::make_shared(ArgNum, isa(ArgType)); if (const auto *ST = dyn_cast(ArgType)) { - if (ST->isInteger() && ST->sizeInBits() < 32) + if (Promote && ST->isInteger() && ST->sizeInBits() < 32) V = std::make_shared(getScalarType("u32"), V); } else if (const auto *PT = dyn_cast(ArgType)) { V = std::make_shared(getScalarType("u32"), V); @@ -1260,6 +1267,11 @@ for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) { Init *TypeInit = ArgsDag->getArg(i); + bool Promote = true; + if (auto TypeDI = dyn_cast(TypeInit)) + if (TypeDI->getDef()->isSubClassOf("unpromoted")) + Promote = false; + // Work out the type of the argument, for use in the function prototype in // the header file. const Type *ArgType = ME.getType(TypeInit, Param); @@ -1269,7 +1281,7 @@ // into the variable-name scope that the code gen will refer to. StringRef ArgName = ArgsDag->getArgNameStr(i); if (!ArgName.empty()) - Scope[ArgName] = ME.getCodeForArg(i, ArgType); + Scope[ArgName] = ME.getCodeForArg(i, ArgType, Promote); // If the argument is a subclass of Immediate, record the details about // what values it can take, for Sema checking. @@ -1288,7 +1300,7 @@ } else if (Bounds->getName() == "IB_LaneIndex") { IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; IA.i1 = 0; - IA.i2 = 128 / Param->sizeInBits(); + IA.i2 = 128 / Param->sizeInBits() - 1; } else if (Bounds->getName() == "IB_EltBit") { IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; IA.i1 = Bounds->getValueAsInt("base");