]> granicus.if.org Git - clang/commitdiff
[AArch64] Corrected FP16 Intrinsic range checks in Clang + added Sema tests
authorLuke Geeson <luke.geeson@arm.com>
Tue, 12 Jun 2018 09:54:27 +0000 (09:54 +0000)
committerLuke Geeson <luke.geeson@arm.com>
Tue, 12 Jun 2018 09:54:27 +0000 (09:54 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@334489 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/arm_fp16.td
lib/Sema/SemaChecking.cpp
test/CodeGen/aarch64-v8.2a-fp16-intrinsics.c
test/Sema/aarch64-neon-fp16-ranges.c [new file with mode: 0644]
utils/TableGen/NeonEmitter.cpp

index 5c7e437b72fe65ac087cb06304824f788764bc83..bc15a22d84a63185a340e7f5f4e65d095b0d30b3 100644 (file)
@@ -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">;
index 6648ffc13fedeca8ceec898c79b388b420eb6d47..d5945ef6f6251eed8bfea4b20db394ed87cfaa74 100644 (file)
@@ -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);
index 0390a87e014cd64920faa1317cf52d561fa49333..b8e1f92a2579e2c9a07c64a3fdcd0f9134abb8aa 100644 (file)
@@ -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/test/Sema/aarch64-neon-fp16-ranges.c b/test/Sema/aarch64-neon-fp16-ranges.c
new file mode 100644 (file)
index 0000000..acd6947
--- /dev/null
@@ -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}}
+}
index f8af4057cb0690e0e34fd1614895b838eb84ed1d..eca03a5892e22ef61c5b132fd5ca9773a1bab463 100644 (file)
@@ -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