diff options
| author | Luke Geeson <luke.geeson@arm.com> | 2018-06-12 09:54:27 +0000 | 
|---|---|---|
| committer | Luke Geeson <luke.geeson@arm.com> | 2018-06-12 09:54:27 +0000 | 
| commit | dc54b3741431683db1e36088c5bf7fc258d06da7 (patch) | |
| tree | 3622eac4f7112b2c71f4a4489ecf029f84db877d | |
| parent | dc82aa44e63cbec7d23f3d88242cda682cdbdfb9 (diff) | |
| download | bcm5719-llvm-dc54b3741431683db1e36088c5bf7fc258d06da7.tar.gz bcm5719-llvm-dc54b3741431683db1e36088c5bf7fc258d06da7.zip  | |
[AArch64] Corrected FP16 Intrinsic range checks in Clang + added Sema tests
Summary:
This fixes the ranges for the vcvth family of FP16 intrinsics in the clang front end. Previously it was accepting incorrect ranges
-Changed builtin range checking in SemaChecking
-added tests SemaCheck changes - included in  their own file since no similar one exists
-modified existing tests to reflect new ranges
Reviewers: SjoerdMeijer, javed.absar
Reviewed By: SjoerdMeijer
Subscribers: kristof.beyls, cfe-commits
Differential Revision: https://reviews.llvm.org/D47592
llvm-svn: 334489
| -rw-r--r-- | clang/include/clang/Basic/arm_fp16.td | 18 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 8 | ||||
| -rw-r--r-- | clang/test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c | 48 | ||||
| -rw-r--r-- | clang/test/Sema/aarch64-neon-fp16-ranges.c | 64 | ||||
| -rw-r--r-- | clang/utils/TableGen/NeonEmitter.cpp | 13 | 
5 files changed, 109 insertions, 42 deletions
diff --git a/clang/include/clang/Basic/arm_fp16.td b/clang/include/clang/Basic/arm_fp16.td index 5c7e437b72f..bc15a22d84a 100644 --- a/clang/include/clang/Basic/arm_fp16.td +++ b/clang/include/clang/Basic/arm_fp16.td @@ -75,15 +75,15 @@ let ArchGuard = "defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) && defined(__aarc    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">; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6648ffc13fe..d5945ef6f62 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1499,10 +1499,10 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {    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); diff --git a/clang/test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c b/clang/test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c index 0390a87e014..b8e1f92a257 100644 --- a/clang/test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c +++ b/clang/test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c @@ -486,90 +486,90 @@ uint16_t test_vclth_f16(float16_t a, float16_t b) {  // 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 diff --git a/clang/test/Sema/aarch64-neon-fp16-ranges.c b/clang/test/Sema/aarch64-neon-fp16-ranges.c new file mode 100644 index 00000000000..acd69474467 --- /dev/null +++ b/clang/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 <arm_neon.h> +#include <arm_fp16.h> + +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}} +} diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp index f8af4057cb0..eca03a5892e 100644 --- a/clang/utils/TableGen/NeonEmitter.cpp +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -2162,8 +2162,7 @@ void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,    OS << "#endif\n\n";  } -void -NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, +void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,                                          SmallVectorImpl<Intrinsic *> &Defs) {    OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; @@ -2188,11 +2187,15 @@ NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,      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  | 

