sepavloff created this revision.
sepavloff added reviewers: rjmccall, aaron.ballman, arsenm, kpn, qiucf, 
efriedma.
Herald added a project: All.
sepavloff requested review of this revision.
Herald added a subscriber: wdng.
Herald added a project: clang.

Builtin function `__builtin_isfpclass` now can be called for a vector
of floating-point values. In this case it is applied to the vector
elementwise and produces vector of boolean values.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153339

Files:
  clang/docs/LanguageExtensions.rst
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/isfpclass.c

Index: clang/test/CodeGen/isfpclass.c
===================================================================
--- clang/test/CodeGen/isfpclass.c
+++ clang/test/CodeGen/isfpclass.c
@@ -1,5 +1,5 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +avx512fp16 -S -O1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature -S -O1 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK-LABEL: define dso_local i1 @check_isfpclass_finite
 // CHECK-SAME: (float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
@@ -84,3 +84,27 @@
 #pragma STDC FENV_ACCESS ON
   return __builtin_isfpclass(x, 96 /*Zero*/);
 }
+
+typedef float __attribute__((ext_vector_type(4))) float4;
+typedef _Bool __attribute__((ext_vector_type(4))) bool4;
+
+// CHECK-LABEL: define dso_local <4 x i1> @check_isfpclass_nan_v4f32
+// CHECK-SAME: (<4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = fcmp uno <4 x float> [[X]], zeroinitializer
+// CHECK-NEXT:    ret <4 x i1> [[TMP0]]
+//
+bool4 check_isfpclass_nan_v4f32(float4 x) {
+  return __builtin_isfpclass(x, 3 /*NaN*/);
+}
+
+// CHECK-LABEL: define dso_local <4 x i1> @check_isfpclass_nan_strict_v4f32
+// CHECK-SAME: (<4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> [[X]], i32 3) #[[ATTR4]]
+// CHECK-NEXT:    ret <4 x i1> [[TMP0]]
+//
+bool4 check_isfpclass_nan_strict_v4f32(float4 x) {
+#pragma STDC FENV_ACCESS ON
+  return __builtin_isfpclass(x, 3 /*NaN*/);
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -7687,14 +7687,15 @@
 
 /// SemaBuiltinSemaBuiltinFPClassification - Handle functions like
 /// __builtin_isnan and friends.  This is declared to take (...), so we have
-/// to check everything. We expect the last argument to be a floating point
-/// value.
+/// to check everything.
 bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
   if (checkArgCount(*this, TheCall, NumArgs))
     return true;
 
+  bool IsFPClass = NumArgs == 2;
+
   // Find out position of floating-point argument.
-  unsigned FPArgNo = (NumArgs == 2) ? 0 : NumArgs - 1;
+  unsigned FPArgNo = IsFPClass ? 0 : NumArgs - 1;
 
   // We can count on all parameters preceding the floating-point just being int.
   // Try all of those.
@@ -7725,18 +7726,36 @@
     OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get();
   TheCall->setArg(FPArgNo, OrigArg);
 
+  const VectorType *VectorArgTy = nullptr;
+  QualType ElementTy = OrigArg->getType();
+  // TODO: When all classification function are implemented with is_fpclass,
+  // vector argument can be supported in all of them.
+  if (ElementTy->isVectorType() && IsFPClass) {
+    VectorArgTy = ElementTy->getAs<VectorType>();
+    ElementTy = VectorArgTy->getElementType();
+  }
+
   // This operation requires a non-_Complex floating-point number.
-  if (!OrigArg->getType()->isRealFloatingType())
+  if (!ElementTy->isRealFloatingType())
     return Diag(OrigArg->getBeginLoc(),
                 diag::err_typecheck_call_invalid_unary_fp)
            << OrigArg->getType() << OrigArg->getSourceRange();
 
   // __builtin_isfpclass has integer parameter that specify test mask. It is
   // passed in (...), so it should be analyzed completely here.
-  if (NumArgs == 2)
+  if (IsFPClass)
     if (SemaBuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags))
       return true;
 
+  // TODO: enable this code to all classification functions.
+  if (IsFPClass) {
+    QualType ResultTy = Context.BoolTy;
+    if (VectorArgTy)
+      ResultTy = Context.getVectorType(ResultTy, VectorArgTy->getNumElements(),
+                                       VectorType::GenericVector);
+    TheCall->setType(ResultTy);
+  }
+
   return false;
 }
 
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -3496,18 +3496,15 @@
 ``__builtin_isfpclass``
 -----------------------
 
-``__builtin_isfpclass`` is used to test if the specified floating-point value
-falls into one of the specified floating-point classes.
+``__builtin_isfpclass`` is used to test if the specified floating-point values
+fall into one of the specified floating-point classes.
 
 **Syntax**:
 
 .. code-block:: c++
 
-    int __builtin_isfpclass(fp_type expr, int mask)
-
-``fp_type`` is a floating-point type supported by the target. ``mask`` is an
-integer constant expression, where each bit represents floating-point class to
-test. The function returns boolean value.
+    bool __builtin_isfpclass(fp_type expr, int mask)
+    boolean_vector __builtin_isfpclass(fp_vector expr, int mask)
 
 **Example of use**:
 
@@ -3515,7 +3512,7 @@
 
   if (__builtin_isfpclass(x, 448)) {
      // `x` is positive finite value
-	 ...
+     ...
   }
 
 **Description**:
@@ -3523,8 +3520,9 @@
 The ``__builtin_isfpclass()`` builtin is a generalization of functions ``isnan``,
 ``isinf``, ``isfinite`` and some others defined by the C standard. It tests if
 the floating-point value, specified by the first argument, falls into any of data
-classes, specified by the second argument. The later is a bitmask, in which each
-data class is represented by a bit using the encoding:
+classes, specified by the second argument. The latter is an integer constant
+expression, that represents a bitmask, in which each data class is represented by
+a bit using the encoding:
 
 ========== =================== ======================
 Mask value Data class          Macro
@@ -3552,6 +3550,13 @@
 is identical to ``isnan``,``__builtin_isfpclass(x, 504)`` - to ``isfinite``
 and so on.
 
+If the first argument is a vector, the function is equivalent to the set of
+scalar calls of ``__builtin_isfpclass`` applied to the input elementwise.
+
+The result of ``__builtin_isfpclass`` is a boolean value, if the first argument
+is a scalar, or a boolean vector with the same vector length as the first
+argument.
+
 This function never raises floating-point exceptions and does not canonicalize
 its input. The floating-point argument is not promoted, its data class is
 determined based on its representation in its actual semantic type.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to