Index: include/clang/Basic/arm_fp16.td =================================================================== --- include/clang/Basic/arm_fp16.td +++ include/clang/Basic/arm_fp16.td @@ -75,15 +75,15 @@ def SCALAR_FCVTPUH : SInst<"vcvtp_u16", "bs", "Sh">; def SCALAR_FCVTPUH1 : SInst<"vcvtp_u32", "Us", "Sh">; def SCALAR_FCVTPUH2 : SInst<"vcvtp_u64", "Os", "Sh">; - - def SCALAR_SCVTFSHO : SInst<"vcvth_n_f16", "Ysi", "silUsUiUl">; - def SCALAR_FCVTZSHO : SInst<"vcvt_n_s16", "$si", "Sh">; - def SCALAR_FCVTZSH1O: SInst<"vcvt_n_s32", "Isi", "Sh">; - def SCALAR_FCVTZSH2O: SInst<"vcvt_n_s64", "Lsi", "Sh">; - def SCALAR_FCVTZUHO : SInst<"vcvt_n_u16", "bsi", "Sh">; - def SCALAR_FCVTZUH1O: SInst<"vcvt_n_u32", "Usi", "Sh">; - def SCALAR_FCVTZUH2O: SInst<"vcvt_n_u64", "Osi", "Sh">; - + let isVCVT_N = 1 in { + def SCALAR_SCVTFSHO : SInst<"vcvth_n_f16", "Ysi", "silUsUiUl">; + def SCALAR_FCVTZSHO : SInst<"vcvt_n_s16", "$si", "Sh">; + def SCALAR_FCVTZSH1O: SInst<"vcvt_n_s32", "Isi", "Sh">; + def SCALAR_FCVTZSH2O: SInst<"vcvt_n_s64", "Lsi", "Sh">; + def SCALAR_FCVTZUHO : SInst<"vcvt_n_u16", "bsi", "Sh">; + def SCALAR_FCVTZUH1O: SInst<"vcvt_n_u32", "Usi", "Sh">; + def SCALAR_FCVTZUH2O: SInst<"vcvt_n_u64", "Osi", "Sh">; + } // Comparison def SCALAR_CMEQRH : SInst<"vceq", "bss", "Sh">; def SCALAR_CMEQZH : SInst<"vceqz", "bs", "Sh">; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1458,10 +1458,10 @@ switch (BuiltinID) { default: return false; -#define GET_NEON_IMMEDIATE_CHECK -#include "clang/Basic/arm_neon.inc" -#include "clang/Basic/arm_fp16.inc" -#undef GET_NEON_IMMEDIATE_CHECK + #define GET_NEON_IMMEDIATE_CHECK + #include "clang/Basic/arm_neon.inc" + #include "clang/Basic/arm_fp16.inc" + #undef GET_NEON_IMMEDIATE_CHECK } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); Index: test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c =================================================================== --- test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c +++ test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c @@ -486,90 +486,90 @@ // CHECK-LABEL: test_vcvth_n_f16_s16 // CHECK: [[SEXT:%.*]] = sext i16 %a to i32 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i32(i32 [[SEXT]], i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i32(i32 [[SEXT]], i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_s16(int16_t a) { - return vcvth_n_f16_s16(a, 0); + return vcvth_n_f16_s16(a, 1); } // CHECK-LABEL: test_vcvth_n_f16_s32 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i32(i32 %a, i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i32(i32 %a, i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_s32(int32_t a) { - return vcvth_n_f16_s32(a, 0); + return vcvth_n_f16_s32(a, 1); } // CHECK-LABEL: test_vcvth_n_f16_s64 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i64(i64 %a, i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxs2fp.f16.i64(i64 %a, i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_s64(int64_t a) { - return vcvth_n_f16_s64(a, 0); + return vcvth_n_f16_s64(a, 1); } // CHECK-LABEL: test_vcvth_n_s16_f16 -// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) // CHECK: [[RET:%.*]] = trunc i32 [[CVT]] to i16 // CHECK: ret i16 [[RET]] int16_t test_vcvth_n_s16_f16(float16_t a) { - return vcvth_n_s16_f16(a, 0); + return vcvth_n_s16_f16(a, 1); } // CHECK-LABEL: test_vcvth_n_s32_f16 -// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) // CHECK: ret i32 [[CVT]] int32_t test_vcvth_n_s32_f16(float16_t a) { - return vcvth_n_s32_f16(a, 0); + return vcvth_n_s32_f16(a, 1); } // CHECK-LABEL: test_vcvth_n_s64_f16 -// CHECK: [[CVT:%.*]] = call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 1) // CHECK: ret i64 [[CVT]] int64_t test_vcvth_n_s64_f16(float16_t a) { - return vcvth_n_s64_f16(a, 0); + return vcvth_n_s64_f16(a, 1); } // CHECK-LABEL: test_vcvth_n_f16_u16 // CHECK: [[SEXT:%.*]] = zext i16 %a to i32 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32 [[SEXT]], i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32 [[SEXT]], i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_u16(int16_t a) { - return vcvth_n_f16_u16(a, 0); + return vcvth_n_f16_u16(a, 1); } // CHECK-LABEL: test_vcvth_n_f16_u32 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32 %a, i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32 %a, i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_u32(int32_t a) { - return vcvth_n_f16_u32(a, 0); + return vcvth_n_f16_u32(a, 1); } // CHECK-LABEL: test_vcvth_n_f16_u64 -// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i64(i64 %a, i32 0) +// CHECK: [[CVT:%.*]] = call half @llvm.aarch64.neon.vcvtfxu2fp.f16.i64(i64 %a, i32 1) // CHECK: ret half [[CVT]] float16_t test_vcvth_n_f16_u64(int64_t a) { - return vcvth_n_f16_u64(a, 0); + return vcvth_n_f16_u64(a, 1); } // CHECK-LABEL: test_vcvth_n_u16_f16 -// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) // CHECK: [[RET:%.*]] = trunc i32 [[CVT]] to i16 // CHECK: ret i16 [[RET]] int16_t test_vcvth_n_u16_f16(float16_t a) { - return vcvth_n_u16_f16(a, 0); + return vcvth_n_u16_f16(a, 1); } // CHECK-LABEL: test_vcvth_n_u32_f16 -// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) // CHECK: ret i32 [[CVT]] int32_t test_vcvth_n_u32_f16(float16_t a) { - return vcvth_n_u32_f16(a, 0); + return vcvth_n_u32_f16(a, 1); } // CHECK-LABEL: test_vcvth_n_u64_f16 -// CHECK: [[CVT:%.*]] = call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 0) +// CHECK: [[CVT:%.*]] = call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 1) // CHECK: ret i64 [[CVT]] int64_t test_vcvth_n_u64_f16(float16_t a) { - return vcvth_n_u64_f16(a, 0); + return vcvth_n_u64_f16(a, 1); } // CHECK-LABEL: test_vdivh_f16 Index: test/Sema/aarch64-neon-fp16-ranges.c =================================================================== --- /dev/null +++ test/Sema/aarch64-neon-fp16-ranges.c @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -triple arm64-linux-gnu -fallow-half-arguments-and-returns -target-feature +neon -target-feature +fullfp16 -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fallow-half-arguments-and-returns -target-feature +fullfp16 -target-feature +neon -ffreestanding -fsyntax-only -verify %s + +#include +#include + +void test_vcvt_f16_16(int16_t a){ + vcvth_n_f16_s16(a, 1); + vcvth_n_f16_s16(a, 16); + vcvth_n_f16_s16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_f16_s16(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_f16_u16(a, 1); + vcvth_n_f16_u16(a, 16); + vcvth_n_f16_u16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_f16_u16(a, 17); // expected-error {{argument should be a value from 1 to 16}} +} + +void test_vcvt_f16_32(int32_t a){ + vcvth_n_f16_u32(a, 1); + vcvth_n_f16_u32(a, 16); + vcvth_n_f16_u32(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_f16_u32(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_f16_s32(a, 1); + vcvth_n_f16_s32(a, 16); + vcvth_n_f16_s32(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_f16_s32(a, 17); // expected-error {{argument should be a value from 1 to 16}} +} + +void test_vcvt_f16_64(int64_t a){ + vcvth_n_f16_s64(a, 1); + vcvth_n_f16_s64(a, 16); + vcvth_n_f16_s64(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_f16_s64(a, 17); // expected-error {{argument should be a value from 1 to 16}} +} + + +void test_vcvt_su_f(float16_t a){ + vcvth_n_s16_f16(a, 1); + vcvth_n_s16_f16(a, 16); + vcvth_n_s16_f16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_s16_f16(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_s32_f16(a, 1); + vcvth_n_s32_f16(a, 16); + vcvth_n_s32_f16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_s32_f16(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_s64_f16(a, 1); + vcvth_n_s64_f16(a, 16); + vcvth_n_s64_f16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_s64_f16(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_u16_f16(a, 1); + vcvth_n_u16_f16(a, 16); + vcvth_n_u16_f16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_u16_f16(a, 17); // expected-error {{argument should be a value from 1 to 16}} + + vcvth_n_u32_f16(a, 1); + vcvth_n_u32_f16(a, 16); + vcvth_n_u32_f16(a, 0); // expected-error {{argument should be a value from 1 to 16}} + vcvth_n_u32_f16(a, 17); // expected-error {{argument should be a value from 1 to 16}} +} Index: utils/TableGen/NeonEmitter.cpp =================================================================== --- utils/TableGen/NeonEmitter.cpp +++ utils/TableGen/NeonEmitter.cpp @@ -2162,8 +2162,7 @@ OS << "#endif\n\n"; } -void -NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, +void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, SmallVectorImpl &Defs) { OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; @@ -2188,11 +2187,15 @@ Record *R = Def->getRecord(); if (R->getValueAsBit("isVCVT_N")) { // VCVT between floating- and fixed-point values takes an immediate - // in the range [1, 32) for f32 or [1, 64) for f64. + // in the range [1, 32) for f32 or [1, 64) for f64 or [1, 16) for f16. LowerBound = "1"; - if (Def->getBaseType().getElementSizeInBits() == 32) + if (Def->getBaseType().getElementSizeInBits() == 16 || + Def->getName().find('h') != std::string::npos) + // VCVTh operating on FP16 intrinsics in range [1, 16) + UpperBound = "15"; + else if (Def->getBaseType().getElementSizeInBits() == 32) UpperBound = "31"; - else + else UpperBound = "63"; } else if (R->getValueAsBit("isScalarShift")) { // Right shifts have an 'r' in the name, left shifts do not. Convert