https://github.com/chinmaydd updated 
https://github.com/llvm/llvm-project/pull/212647

>From 476eb9d1f5db5351061e21dc34f5b8158fe83ceb Mon Sep 17 00:00:00 2001
From: Chinmay Deshpande <[email protected]>
Date: Mon, 27 Jul 2026 14:49:02 -0400
Subject: [PATCH 1/2] [clang] Add elementwise conversions from encoded FP8
 values

Add nine builtins converting Float8E5M2, Float8E4M3FN, and Float8E5M3FNU
encodings to _Float16, __bf16, or float through
llvm.convert.from.arbitrary.fp.

Accept exactly 8-bit integer scalars and generic fixed-length vectors,
preserving vector kinds and element counts without integer promotions.
Also support scalar AArch64 __mfp8 containers. Apply destination type
availability checks, including deferred offload diagnostics, and reject
constant-expression use.

Document the interface and add semantic, template, language-mode,
target-specific, and IR-generation regression coverage.
---
 clang/docs/LanguageExtensions.md              |  97 ++++++++++
 clang/docs/ReleaseNotes.md                    |   3 +
 .../clang/Basic/ArbitraryFPFormats.def        |  30 +++
 clang/include/clang/Basic/Builtins.td         |  18 ++
 .../clang/Basic/DiagnosticSemaKinds.td        |  10 +
 clang/include/clang/Sema/Sema.h               |   6 +
 clang/lib/CodeGen/CGBuiltin.cpp               |  31 ++++
 clang/lib/Sema/SemaChecking.cpp               | 105 +++++++++++
 clang/lib/Sema/SemaType.cpp                   |  68 +++++--
 ...ns-elementwise-convert-from-arbitrary-fp.c | 172 ++++++++++++++++++
 ...ementwise-convert-from-arbitrary-fp-neon.c |  23 +++
 ...lementwise-convert-from-arbitrary-fp-rvv.c |   5 +
 ...entwise-convert-from-arbitrary-fp-target.c |  44 +++++
 ...ns-elementwise-convert-from-arbitrary-fp.c | 135 ++++++++++++++
 ...-elementwise-convert-from-arbitrary-fp.cpp |  37 ++++
 ...s-elementwise-convert-from-arbitrary-fp.cl |  38 ++++
 16 files changed, 804 insertions(+), 18 deletions(-)
 create mode 100644 clang/include/clang/Basic/ArbitraryFPFormats.def
 create mode 100644 
clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
 create mode 100644 
clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
 create mode 100644 
clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
 create mode 100644 
clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-target.c
 create mode 100644 
clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
 create mode 100644 
clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
 create mode 100644 
clang/test/SemaOpenCL/builtins-elementwise-convert-from-arbitrary-fp.cl

diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index 3db8d083c4075..dfff19ee3bd93 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -3682,6 +3682,103 @@ C-style cast applied to each element of the first 
argument.
 
 Query for this feature with `__has_builtin(__builtin_convertvector)`.
 
+(langext-builtin-elementwise-convert-from-arbitrary-fp)=
+
+### `__builtin_elementwise_convert_from_*`
+
+The `__builtin_elementwise_convert_from_*` family interprets an integer as the 
bits of a narrow floating-point format that has no corresponding C type and 
converts it to a native floating-point type.
+
+**Syntax**:
+
+```c++
+__builtin_elementwise_convert_from_<source_format>_<destination_type>(bits)
+```
+
+**Examples**:
+
+```c++
+typedef unsigned char uchar4 __attribute__((ext_vector_type(4)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+unsigned char b; uchar4 vb;
+
+// Interpret b as a Float8E4M3FN value and widen it to _Float16.
+__builtin_elementwise_convert_from_f8e4m3fn_f16(b)
+
+// The same, elementwise, for four Float8E5M2 values.
+__builtin_elementwise_convert_from_f8e5m2_f32(vb)
+```
+
+**Description**:
+
+`bits` is a non-Boolean, non-enumeration integer or a supported fixed-length 
vector of such integers holding the encoded floating-point value.
+The result is a scalar for a scalar input or a vector with the same number of 
elements for a vector input.
+Supported vector kinds are GNU `vector_size` and Clang/OpenCL 
`ext_vector_type`.
+The result preserves which of those two vector kinds the input uses.
+Sizeless vectors and target-specific fixed-length vector kinds are rejected.
+Preserving both the lane count and a target-specific vector kind after widening
+the element type can produce an invalid type or ABI combination, such as a
+widened NEON vector.
+
+The source format suffix determines the interpretation and required integer 
element width:
+
+| Suffix       | Source format  | Width |
+| ------------ | -------------- | ----- |
+| `f8e5m2`     | `Float8E5M2`   | 8     |
+| `f8e4m3fn`   | `Float8E4M3FN` | 8     |
+| `f8e5m3fnu`  | `Float8E5M3FNU`| 8     |
+
+The destination suffix determines the result element type:
+
+| Suffix | Result element type |
+| ------ | ------------------- |
+| `f16`  | `_Float16`          |
+| `bf16` | `__bf16`            |
+| `f32`  | `float`             |
+
+The `f16` suffix denotes `_Float16` in every language mode, including OpenCL.
+The three source suffixes and three destination suffixes form exactly nine
+builtin spellings.
+
+`Float8E5M3FNU` has no sign bit and no infinity encoding, and its exponent
+range exceeds that of `_Float16`. Its seven largest finite encodings therefore
+convert to infinity rather than exactly when the destination is `f16`; the
+`bf16` and `f32` destinations are exact.
+
+Only the signedness-free width of `bits` matters, so for an 8-bit format any 
8-bit `char`, `signed char`, `unsigned char`, or `_BitInt(8)` of either 
signedness may be used.
+On targets that have it, `__mfp8` is also accepted as a scalar source, because
+it is an opaque 8-bit floating-point container with no interpretation of its
+own. Its Neon vector types are rejected with the other target-specific vector
+kinds.
+
+Integer promotions and the usual arithmetic conversions are not applied to
+`bits`, so an expression that C promotes to `int` needs an explicit cast back
+to an 8-bit container:
+
+```c
+unsigned char b;
+__builtin_elementwise_convert_from_f8e5m2_f32((unsigned char)(b >> 1));
+```
+
+These builtins are available in C, C++, and OpenCL, but are not supported in 
constant expressions.
+`__has_constexpr_builtin` therefore returns zero for these builtins.
+Each builtin maps to the `llvm.convert.from.arbitrary.fp` intrinsic; see its 
description in the LLVM Language Reference for the exact conversion semantics.
+NaN results follow LLVM's general NaN rules; the sign, quiet or signaling 
state,
+and payload are not guaranteed to be preserved.
+Current generic code generation for the intrinsic is SelectionDAG-only.
+Other code-generation paths are future work.
+
+Normal target and language availability rules apply to the result element type.
+
+**Builtin availability**:
+
+Use `__has_builtin`, for example
+`__has_builtin(__builtin_elementwise_convert_from_f8e4m3fn_f16)`, to test
+whether Clang supports that exact builtin spelling.
+This does not establish destination type availability, native instruction
+availability, or backend-lowering availability.
+Code using `_Float16` or `__bf16` must check type availability separately.
+
 ### `__builtin_bitreverse`
 
 - `__builtin_bitreverse8`
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77a1e73bc8af6..3d5178af7e0af 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -256,6 +256,9 @@ features cannot lower the translation-unit ABI level;
 
 - Clang now allows GNU computed `goto` extension in `constexpr` functions, 
matching the relaxed
   `constexpr` function body rules introduced in C++23.
+- Added the `__builtin_elementwise_convert_from_*` family, which converts
+  integer-encoded `Float8E5M2`, `Float8E4M3FN`, and `Float8E5M3FNU` values,
+  scalar or in a fixed-length vector, to `_Float16`, `__bf16`, or `float`.
 
 - Added support for the `__builtin_strlcat` and `__builtin_strlcpy` builtins.
 
diff --git a/clang/include/clang/Basic/ArbitraryFPFormats.def 
b/clang/include/clang/Basic/ArbitraryFPFormats.def
new file mode 100644
index 0000000000000..a2696154d840e
--- /dev/null
+++ b/clang/include/clang/Basic/ArbitraryFPFormats.def
@@ -0,0 +1,30 @@
+//===--- ArbitraryFPFormats.def - Arbitrary FP format database --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Source encodings exposed by the __builtin_elementwise_convert_from_* family.
+// Src is the source half of the builtin name suffix; LLVMName is the
+// llvm.convert.from.arbitrary.fp interpretation string.
+//
+// Each entry needs a matching instantiation in Builtins.td: expansions name
+// builtin IDs directly, so a stale entry fails to compile. An entry must also
+// be accepted by APFloat::getArbitraryFPSemantics, or lowering fails.
+//
+// The sub-byte encodings (Float6E3M2FN, Float6E2M3FN, Float4E2M1FN) lower but
+// are not exposed; Clang cannot spell their vector element types coherently.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARBITRARY_FP_FORMAT
+#define ARBITRARY_FP_FORMAT(Src, LLVMName)
+#endif
+
+ARBITRARY_FP_FORMAT(f8e5m2, "Float8E5M2")
+ARBITRARY_FP_FORMAT(f8e4m3fn, "Float8E4M3FN")
+ARBITRARY_FP_FORMAT(f8e5m3fnu, "Float8E5M3FNU")
+
+#undef ARBITRARY_FP_FORMAT
diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index ad9a58bb2ad2d..69b69cb28682e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1481,6 +1481,24 @@ def ConvertVector : Builtin {
   let Prototype = "void(...)";
 }
 
+// Keep the instantiations below in sync with ArbitraryFPFormats.def.
+multiclass ElementwiseConvertFromArbitraryFP<string Src> {
+  foreach Dst = ["f16", "bf16", "f32"] in {
+    def _#Dst : Builtin {
+      let Spellings = ["__builtin_elementwise_convert_from_" # Src # "_" # 
Dst];
+      let Attributes = [NoThrow, Const, CustomTypeChecking];
+      let Prototype = "void(...)";
+    }
+  }
+}
+
+defm ElementwiseConvertFromF8E5M2
+    : ElementwiseConvertFromArbitraryFP<"f8e5m2">;
+defm ElementwiseConvertFromF8E4M3FN
+    : ElementwiseConvertFromArbitraryFP<"f8e4m3fn">;
+defm ElementwiseConvertFromF8E5M3FNU
+    : ElementwiseConvertFromArbitraryFP<"f8e5m3fnu">;
+
 def MaskedLoad : Builtin {
   let Spellings = ["__builtin_masked_load"];
   let Attributes = [NoThrow, CustomTypeChecking];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 700d8f5684ef9..b458ecb4d4d82 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11485,6 +11485,16 @@ def err_builtin_non_vector_type : Error<
 def err_convertvector_incompatible_vector : Error<
   "first two arguments to __builtin_convertvector must have the same number of 
elements">;
 
+def err_arbitrary_fp_source_type : Error<
+  "argument of type %0 cannot hold an '%1' encoding; expected an integer of "
+  "exactly %2 bits, a vector of such integers, or __mfp8">;
+def err_arbitrary_fp_source_width : Error<
+  "%select{argument type|vector element type}0 %1 must be exactly %2 bits "
+  "wide to hold an '%3' encoding">;
+def err_arbitrary_fp_unsupported_vector : Error<
+  "argument of type %0 has an unsupported vector kind; only GNU "
+  "'vector_size' and Clang 'ext_vector_type' vectors are supported">;
+
 def err_first_argument_to_cwsc_not_call : Error<
   "first argument to __builtin_call_with_static_chain must be a non-member 
call expression">;
 def err_first_argument_to_cwsc_block_call : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2c4986d56eede..67079fc7d6fb5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1182,6 +1182,12 @@ class Sema final : public SemaBase {
   void checkTypeSupport(QualType Ty, SourceLocation Loc,
                         ValueDecl *D = nullptr);
 
+  /// Check if the floating-point type is supported in the current language
+  /// mode and target. If \p DiagnoseTarget is true, diagnose offload code
+  /// according to whether its enclosing function is emitted.
+  bool checkFloatingPointTypeSupport(QualType Ty, SourceLocation Loc,
+                                     bool DiagnoseTarget = false);
+
   /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
   /// cast.  If there is already an implicit cast, merge into the existing one.
   /// If isLvalue, the result of the cast is an lvalue.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 233609605fb21..7cf18aaa8c80e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4345,6 +4345,37 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     return RValue::get(Result);
   }
 
+#define ARBITRARY_FP_FORMAT(Src, LLVMName)                                     
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f16:              
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_bf16:             
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f32:
+#include "clang/Basic/ArbitraryFPFormats.def"
+    {
+      StringRef FormatName;
+      switch (BuiltinID) {
+#define ARBITRARY_FP_FORMAT(Src, LLVMName)                                     
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f16:              
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_bf16:             
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f32:              
\
+    FormatName = LLVMName;                                                     
\
+    break;
+#include "clang/Basic/ArbitraryFPFormats.def"
+      default:
+        llvm_unreachable("builtin is missing from ArbitraryFPFormats.def");
+      }
+
+      Value *Src = EmitScalarExpr(E->getArg(0));
+      // __mfp8 lowers to <1 x i8>; the intrinsic wants a plain i8.
+      if (E->getArg(0)->getType()->isMFloat8Type())
+        Src = Builder.CreateBitCast(Src, Builder.getInt8Ty());
+      llvm::Type *DstTy = ConvertType(E->getType());
+      llvm::Function *F = CGM.getIntrinsic(
+          llvm::Intrinsic::convert_from_arbitrary_fp, {DstTy, Src->getType()});
+      llvm::Value *Format = llvm::MetadataAsValue::get(
+          getLLVMContext(), llvm::MDString::get(getLLVMContext(), FormatName));
+      return RValue::get(Builder.CreateCall(F, {Src, Format}));
+    }
+
   case Builtin::BI__builtin_elementwise_abs: {
     Value *Result;
     QualType QT = E->getArg(0)->getType();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0531dfa877fbd..a64576b2e7287 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3150,6 +3150,102 @@ static QualType getVectorElementType(ASTContext 
&Context, QualType VecTy) {
   return QualType();
 }
 
+/// Decode a __builtin_elementwise_convert_from_<Src>_<Dst> builtin ID into its
+/// llvm.convert.from.arbitrary.fp interpretation, the source suffix as 
spelled,
+/// and the destination element type.
+static bool getArbitraryFPConversion(ASTContext &Ctx, unsigned BuiltinID,
+                                     StringRef &Interpretation,
+                                     StringRef &SrcSuffix, QualType &DstEltTy) 
{
+  switch (BuiltinID) {
+#define ARBITRARY_FP_FORMAT(Src, LLVMName)                                     
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f16:              
\
+    Interpretation = LLVMName;                                                 
\
+    SrcSuffix = #Src;                                                          
\
+    DstEltTy = Ctx.Float16Ty;                                                  
\
+    return true;                                                               
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_bf16:             
\
+    Interpretation = LLVMName;                                                 
\
+    SrcSuffix = #Src;                                                          
\
+    DstEltTy = Ctx.BFloat16Ty;                                                 
\
+    return true;                                                               
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f32:              
\
+    Interpretation = LLVMName;                                                 
\
+    SrcSuffix = #Src;                                                          
\
+    DstEltTy = Ctx.FloatTy;                                                    
\
+    return true;
+#include "clang/Basic/ArbitraryFPFormats.def"
+  default:
+    return false;
+  }
+}
+
+static bool BuiltinElementwiseConvertFromArbitraryFP(Sema &S, CallExpr 
*TheCall,
+                                                     unsigned BuiltinID) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+
+  StringRef Interpretation, SrcSuffix;
+  QualType DstEltTy;
+  if (!getArbitraryFPConversion(S.Context, BuiltinID, Interpretation, 
SrcSuffix,
+                                DstEltTy))
+    llvm_unreachable("builtin is missing from ArbitraryFPFormats.def");
+
+  if (S.checkFloatingPointTypeSupport(DstEltTy, TheCall->getBeginLoc(),
+                                      /*DiagnoseTarget=*/true))
+    return true;
+
+  ExprResult ConvertedSrc = S.DefaultLvalueConversion(TheCall->getArg(0));
+  if (ConvertedSrc.isInvalid())
+    return true;
+  TheCall->setArg(0, ConvertedSrc.get());
+
+  Expr *Src = ConvertedSrc.get();
+  QualType SrcTy = Src->getType();
+  if (SrcTy->isDependentType()) {
+    TheCall->setType(S.Context.DependentTy);
+    return false;
+  }
+
+  unsigned FormatBits =
+      llvm::APFloatBase::getArbitraryFPFormatSizeInBits(Interpretation);
+
+  // __mfp8 is an opaque 8-bit container, so this builtin supplies the missing
+  // interpretation. Its Neon vector types stay rejected below.
+  if (SrcTy->isMFloat8Type() && FormatBits == 8) {
+    TheCall->setType(DstEltTy);
+    return false;
+  }
+
+  const auto *SrcVecTy = SrcTy->getAs<VectorType>();
+  QualType SrcEltTy = SrcVecTy ? SrcVecTy->getElementType() : SrcTy;
+
+  if (SrcTy->isSizelessVectorType() ||
+      (SrcVecTy && !SrcTy->isExtVectorType() &&
+       SrcVecTy->getVectorKind() != VectorKind::Generic))
+    return S.Diag(Src->getBeginLoc(), 
diag::err_arbitrary_fp_unsupported_vector)
+           << SrcTy << Src->getSourceRange();
+
+  if (!SrcEltTy->isIntegerType() || SrcEltTy->isBooleanType() ||
+      SrcEltTy->isEnumeralType())
+    return S.Diag(Src->getBeginLoc(), diag::err_arbitrary_fp_source_type)
+           << SrcTy << SrcSuffix << FormatBits << Src->getSourceRange();
+
+  if (S.Context.getIntWidth(SrcEltTy) != FormatBits)
+    return S.Diag(Src->getBeginLoc(), diag::err_arbitrary_fp_source_width)
+           << (SrcVecTy != nullptr) << SrcEltTy << FormatBits << SrcSuffix
+           << Src->getSourceRange();
+
+  QualType DstTy = DstEltTy;
+  if (SrcVecTy)
+    DstTy =
+        SrcTy->isExtVectorType()
+            ? S.Context.getExtVectorType(DstEltTy, SrcVecTy->getNumElements())
+            : S.Context.getVectorType(DstEltTy, SrcVecTy->getNumElements(),
+                                      VectorKind::Generic);
+  TheCall->setType(DstTy);
+  return false;
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
                                CallExpr *TheCall) {
@@ -3867,6 +3963,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
       return ExprError();
     break;
 
+#define ARBITRARY_FP_FORMAT(Src, LLVMName)                                     
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f16:              
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_bf16:             
\
+  case Builtin::BI__builtin_elementwise_convert_from_##Src##_f32:
+#include "clang/Basic/ArbitraryFPFormats.def"
+    if (BuiltinElementwiseConvertFromArbitraryFP(*this, TheCall, BuiltinID))
+      return ExprError();
+    break;
+
   // These builtins restrict the element type to floating point
   // types only.
   case Builtin::BI__builtin_elementwise_acos:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 1cb96b556971a..03713d90d6799 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -897,6 +897,52 @@ TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
   }
 }
 
+bool Sema::checkFloatingPointTypeSupport(QualType Ty, SourceLocation Loc,
+                                         bool DiagnoseTarget) {
+  if (Ty->isFloat16Type()) {
+    if (!Context.getTargetInfo().hasFloat16Type()) {
+      if (!getLangOpts().CUDA &&
+          !(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice)) {
+        Diag(Loc, diag::err_type_unsupported) << "_Float16";
+        return true;
+      }
+      if (DiagnoseTarget)
+        return targetDiag(Loc, diag::err_type_unsupported) << "_Float16";
+    }
+    return false;
+  }
+
+  if (Ty->isBFloat16Type()) {
+    if (!Context.getTargetInfo().hasBFloat16Type()) {
+      if (!(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice) &&
+          !getLangOpts().SYCLIsDevice) {
+        Diag(Loc, diag::err_type_unsupported) << "__bf16";
+        return true;
+      }
+      if (DiagnoseTarget)
+        return targetDiag(Loc, diag::err_type_unsupported) << "__bf16";
+    }
+    return false;
+  }
+
+  if (!getLangOpts().OpenCL ||
+      (Ty != Context.DoubleTy && Ty != Context.LongDoubleTy))
+    return false;
+
+  if (!getOpenCLOptions().isSupported("cl_khr_fp64", getLangOpts())) {
+    Diag(Loc, diag::err_opencl_requires_extension)
+        << 0 << Ty
+        << (getLangOpts().getOpenCLCompatibleVersion() >= 300
+                ? "cl_khr_fp64 and __opencl_c_fp64"
+                : "cl_khr_fp64");
+    return true;
+  }
+
+  if (!getOpenCLOptions().isAvailableOption("cl_khr_fp64", getLangOpts()))
+    Diag(Loc, diag::ext_opencl_double_without_pragma);
+  return false;
+}
+
 /// Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1161,18 +1207,13 @@ static QualType 
ConvertDeclSpecToType(TypeProcessingState &state) {
     // CUDA host and device may have different _Float16 support, therefore
     // do not diagnose _Float16 usage to avoid false alarm.
     // ToDo: more precise diagnostics for CUDA.
-    if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA &&
-        !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice))
-      S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
-        << "_Float16";
+    S.checkFloatingPointTypeSupport(Context.Float16Ty, 
DS.getTypeSpecTypeLoc());
     Result = Context.Float16Ty;
     break;
   case DeclSpec::TST_half:    Result = Context.HalfTy; break;
   case DeclSpec::TST_BFloat16:
-    if (!S.Context.getTargetInfo().hasBFloat16Type() &&
-        !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice) &&
-        !S.getLangOpts().SYCLIsDevice)
-      S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__bf16";
+    S.checkFloatingPointTypeSupport(Context.BFloat16Ty,
+                                    DS.getTypeSpecTypeLoc());
     Result = Context.BFloat16Ty;
     break;
   case DeclSpec::TST_float:   Result = Context.FloatTy; break;
@@ -1181,16 +1222,7 @@ static QualType 
ConvertDeclSpecToType(TypeProcessingState &state) {
       Result = Context.LongDoubleTy;
     else
       Result = Context.DoubleTy;
-    if (S.getLangOpts().OpenCL) {
-      if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
-        S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
-            << 0 << Result
-            << (S.getLangOpts().getOpenCLCompatibleVersion() >= 300
-                    ? "cl_khr_fp64 and __opencl_c_fp64"
-                    : "cl_khr_fp64");
-      else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", 
S.getLangOpts()))
-        S.Diag(DS.getTypeSpecTypeLoc(), 
diag::ext_opencl_double_without_pragma);
-    }
+    S.checkFloatingPointTypeSupport(Result, DS.getTypeSpecTypeLoc());
     break;
   case DeclSpec::TST_float128:
     if (!S.Context.getTargetInfo().hasFloat128Type() &&
diff --git 
a/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c 
b/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
new file mode 100644
index 0000000000000..01289993d5d6e
--- /dev/null
+++ b/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
@@ -0,0 +1,172 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | 
FileCheck %s
+
+typedef unsigned char v4u8 __attribute__((ext_vector_type(4)));
+typedef float v4f32 __attribute__((ext_vector_type(4)));
+typedef _Float16 v4f16 __attribute__((ext_vector_type(4)));
+typedef unsigned char g4u8 __attribute__((vector_size(4)));
+typedef float g4f32 __attribute__((vector_size(16)));
+
+// CHECK-LABEL: define dso_local float @from_f8e5m2_to_f32(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 [[TMP0]], metadata !"Float8E5M2")
+// CHECK-NEXT:    ret float [[TMP1]]
+//
+float from_f8e5m2_to_f32(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(b);
+}
+
+// CHECK-LABEL: define dso_local half @from_f8e5m2_to_f16(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call half 
@llvm.convert.from.arbitrary.fp.f16.i8(i8 [[TMP0]], metadata !"Float8E5M2")
+// CHECK-NEXT:    ret half [[TMP1]]
+//
+_Float16 from_f8e5m2_to_f16(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f16(b);
+}
+
+// CHECK-LABEL: define dso_local bfloat @from_f8e5m2_to_bf16(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call bfloat 
@llvm.convert.from.arbitrary.fp.bf16.i8(i8 [[TMP0]], metadata !"Float8E5M2")
+// CHECK-NEXT:    ret bfloat [[TMP1]]
+//
+__bf16 from_f8e5m2_to_bf16(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e5m2_bf16(b);
+}
+
+// CHECK-LABEL: define dso_local float @from_f8e4m3fn_to_f32(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 [[TMP0]], metadata !"Float8E4M3FN")
+// CHECK-NEXT:    ret float [[TMP1]]
+//
+float from_f8e4m3fn_to_f32(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e4m3fn_f32(b);
+}
+
+// CHECK-LABEL: define dso_local half @from_f8e4m3fn_to_f16(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call half 
@llvm.convert.from.arbitrary.fp.f16.i8(i8 [[TMP0]], metadata !"Float8E4M3FN")
+// CHECK-NEXT:    ret half [[TMP1]]
+//
+_Float16 from_f8e4m3fn_to_f16(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e4m3fn_f16(b);
+}
+
+// CHECK-LABEL: define dso_local bfloat @from_f8e4m3fn_to_bf16(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call bfloat 
@llvm.convert.from.arbitrary.fp.bf16.i8(i8 [[TMP0]], metadata !"Float8E4M3FN")
+// CHECK-NEXT:    ret bfloat [[TMP1]]
+//
+__bf16 from_f8e4m3fn_to_bf16(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e4m3fn_bf16(b);
+}
+
+// CHECK-LABEL: define dso_local float @from_f8e5m3fnu_to_f32(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 [[TMP0]], metadata !"Float8E5M3FNU")
+// CHECK-NEXT:    ret float [[TMP1]]
+//
+float from_f8e5m3fnu_to_f32(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e5m3fnu_f32(b);
+}
+
+// CHECK-LABEL: define dso_local half @from_f8e5m3fnu_to_f16(
+// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call half 
@llvm.convert.from.arbitrary.fp.f16.i8(i8 [[TMP0]], metadata !"Float8E5M3FNU")
+// CHECK-NEXT:    ret half [[TMP1]]
+//
+_Float16 from_f8e5m3fnu_to_f16(unsigned char b) {
+  return __builtin_elementwise_convert_from_f8e5m3fnu_f16(b);
+}
+
+// CHECK-LABEL: define dso_local float @from_signed_f8e5m2(
+// CHECK-SAME: i8 noundef signext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 [[TMP0]], metadata !"Float8E5M2")
+// CHECK-NEXT:    ret float [[TMP1]]
+//
+float from_signed_f8e5m2(signed char b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(b);
+}
+
+// CHECK-LABEL: define dso_local float @from_atomic_f8e5m2(
+// CHECK-SAME: ptr noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// CHECK-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic i8, ptr [[TMP0]] seq_cst, 
align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 [[ATOMIC_LOAD]], metadata 
!"Float8E5M2")
+// CHECK-NEXT:    ret float [[TMP1]]
+//
+float from_atomic_f8e5m2(_Atomic(unsigned char) *b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(*b);
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @from_v4f8e5m2(
+// CHECK-SAME: i32 noundef [[B_COERCE:%.*]]) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B:%.*]] = alloca <4 x i8>, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca <4 x i8>, align 4
+// CHECK-NEXT:    store i32 [[B_COERCE]], ptr [[B]], align 4
+// CHECK-NEXT:    [[B1:%.*]] = load <4 x i8>, ptr [[B]], align 4
+// CHECK-NEXT:    store <4 x i8> [[B1]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i8>, ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x float> 
@llvm.convert.from.arbitrary.fp.v4f32.v4i8(<4 x i8> [[TMP0]], metadata 
!"Float8E5M2")
+// CHECK-NEXT:    ret <4 x float> [[TMP1]]
+//
+v4f32 from_v4f8e5m2(v4u8 b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(b);
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @from_g4f8e5m2(
+// CHECK-SAME: i32 noundef [[B_COERCE:%.*]]) #[[ATTR2]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B:%.*]] = alloca <4 x i8>, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca <4 x i8>, align 4
+// CHECK-NEXT:    store i32 [[B_COERCE]], ptr [[B]], align 4
+// CHECK-NEXT:    [[B1:%.*]] = load <4 x i8>, ptr [[B]], align 4
+// CHECK-NEXT:    store <4 x i8> [[B1]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i8>, ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x float> 
@llvm.convert.from.arbitrary.fp.v4f32.v4i8(<4 x i8> [[TMP0]], metadata 
!"Float8E5M2")
+// CHECK-NEXT:    ret <4 x float> [[TMP1]]
+//
+g4f32 from_g4f8e5m2(g4u8 b) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(b);
+}
+
diff --git 
a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
new file mode 100644
index 0000000000000..ee2a92c3e385d
--- /dev/null
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
+// RUN:   -fsyntax-only -verify %s
+
+typedef unsigned char uint8x8_t __attribute__((neon_vector_type(8)));
+typedef __mfp8 mfloat8x8_t __attribute__((neon_vector_type(8)));
+
+void test_neon_vector(uint8x8_t src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+}
+
+// __mfp8 is an opaque 8-bit container, so it is accepted for the 8-bit
+// encodings.
+void test_mfp8_scalar(__mfp8 src) {
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_f32(src)), float), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e4m3fn_f16(src)), _Float16),
+      "");
+}
+
+void test_mfp8_vector(mfloat8x8_t src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+}
diff --git 
a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
new file mode 100644
index 0000000000000..7124e55e075af
--- /dev/null
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v -fsyntax-only -verify %s
+
+__rvv_float32m1_t convert(__rvv_uint8m1_t src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+}
diff --git 
a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-target.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-target.c
new file mode 100644
index 0000000000000..4cc56654cc208
--- /dev/null
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-target.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown -DTEST_BF16 \
+// RUN:   -emit-llvm -o /dev/null -verify=bf16 %s
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -DTEST_F16 \
+// RUN:   -emit-llvm -o /dev/null -verify=f16 %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -fopenmp \
+// RUN:   -fopenmp-is-target-device -DTEST_OMP_BF16 \
+// RUN:   -emit-llvm -o /dev/null -verify=omp-bf16 %s
+
+#if !__has_builtin(__builtin_elementwise_convert_from_f8e5m2_f16) ||          \
+    !__has_builtin(__builtin_elementwise_convert_from_f8e5m2_bf16)
+#error "target-independent builtin spellings must remain available"
+#endif
+
+#if defined(TEST_BF16)
+void test_bf16(unsigned char src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_bf16(src); // bf16-error 
{{__bf16 is not supported on this target}}
+}
+#endif
+
+#if defined(TEST_F16)
+void test_f16(unsigned char src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f16(src); // f16-error 
{{_Float16 is not supported on this target}}
+}
+#endif
+
+#if defined(TEST_OMP_BF16)
+void test_omp_bf16_not_emitted(unsigned char src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_bf16(src);
+}
+
+#pragma omp declare target
+void test_omp_bf16(unsigned char src) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_bf16(src); // omp-bf16-error 
{{__bf16 is not supported on this target}}
+}
+
+void test_omp_bf16_sizeof(unsigned char src) {
+  (void)sizeof(__builtin_elementwise_convert_from_f8e5m2_bf16(src)); // 
omp-bf16-error {{__bf16 is not supported on this target}}
+}
+
+void test_omp_bf16_auto(unsigned char src) {
+  __auto_type value = __builtin_elementwise_convert_from_f8e5m2_bf16(src); // 
omp-bf16-error {{__bf16 is not supported on this target}}
+}
+#pragma omp end declare target
+#endif
diff --git a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
new file mode 100644
index 0000000000000..2c60d7356ecd4
--- /dev/null
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
+
+typedef unsigned char v4u8 __attribute__((ext_vector_type(4)));
+typedef unsigned short v4u16 __attribute__((ext_vector_type(4)));
+typedef _Bool v4bool __attribute__((ext_vector_type(4)));
+typedef float v4f32 __attribute__((ext_vector_type(4)));
+typedef _Float16 v4f16 __attribute__((ext_vector_type(4)));
+typedef unsigned char g4u8 __attribute__((vector_size(4)));
+typedef float g4f32 __attribute__((vector_size(16)));
+
+enum __attribute__((packed)) byte_enum {
+  BYTE_ZERO,
+};
+
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m2_f16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m2_bf16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m2_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e5m2_f64), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e4m3fn_f16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e4m3fn_bf16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e4m3fn_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e4m3fn_f64), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m3fnu_f16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m3fnu_bf16), "");
+_Static_assert(
+    __has_builtin(__builtin_elementwise_convert_from_f8e5m3fnu_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e5m3fnu_f64), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e3m2fn_f16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e3m2fn_bf16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e3m2fn_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e3m2fn_f64), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e2m3fn_f16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e2m3fn_bf16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e2m3fn_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f6e2m3fn_f64), "");
+// FP4 is deferred: _BitInt(4) vectors have no coherent memory layout yet.
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f4e2m1fn_f16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f4e2m1fn_bf16), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f4e2m1fn_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f4e2m1fn_f64), "");
+
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e5m2fnuz_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e4m3_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e4m3fnuz_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e4m3b11fnuz_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e3m4_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e8m0fnu_f32), "");
+_Static_assert(
+    !__has_builtin(__builtin_elementwise_convert_from_f8e5m2_f80), "");
+_Static_assert(!__has_builtin(__builtin_convert_from_arbitrary_fp), "");
+
+void test_result_types(unsigned char b, v4u8 vb, g4u8 gb) {
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_f16(b)), _Float16), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_bf16(b)), __bf16), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_f32(b)), float), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_f32(vb)), v4f32), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e5m2_f32(gb)), g4f32), "");
+  _Static_assert(__builtin_types_compatible_p(
+      typeof(__builtin_elementwise_convert_from_f8e4m3fn_f16(vb)), v4f16), "");
+}
+
+void test_source_formats(unsigned char b) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b);
+  (void)__builtin_elementwise_convert_from_f8e4m3fn_f32(b);
+  (void)__builtin_elementwise_convert_from_f8e5m3fnu_f32(b);
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32((signed char)b);
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32((unsigned _BitInt(8))b);
+}
+
+// Integer promotions do not apply to the source.
+void test_no_promotion(unsigned char b) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32((unsigned char)(b >> 1));
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b >> 1); // 
expected-error {{argument type 'int' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+}
+
+void test_arity(unsigned char b) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(); // expected-error 
{{too few arguments}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b, b); // expected-error 
{{too many arguments}}
+}
+
+void test_width(unsigned short b16, unsigned _BitInt(4) b4, v4u16 vb16) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b16); // expected-error 
{{argument type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b4); // expected-error 
{{argument type 'unsigned _BitInt(4)' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb16); // expected-error 
{{vector element type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+}
+
+void test_operand_types(float f, void *p) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(f); // expected-error 
{{argument of type 'float' cannot hold an 'f8e5m2' encoding; expected an 
integer of exactly 8 bits, a vector of such integers, or __mfp8}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(p); // expected-error 
{{argument of type 'void *' cannot hold an 'f8e5m2' encoding; expected an 
integer of exactly 8 bits, a vector of such integers, or __mfp8}}
+}
+
+void test_disallowed_integer_types(_Bool b, enum byte_enum e, v4bool vb) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b); // expected-error 
{{argument of type '_Bool' cannot hold an 'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(e); // expected-error 
{{argument of type 'enum byte_enum' cannot hold an 'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb); // expected-error 
{{cannot hold an 'f8e5m2' encoding}}
+}
+
+void test_volatile_source(volatile unsigned char *b) {
+  __builtin_assume(
+      __builtin_elementwise_convert_from_f8e5m2_f32(*b)); // expected-warning 
{{assumption is ignored because it contains (potential) side-effects}}
+}
diff --git 
a/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp 
b/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
new file mode 100644
index 0000000000000..8e16ad41cc850
--- /dev/null
+++ b/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 \
+// RUN:   -fsyntax-only -verify %s
+
+template <typename Src> float convert(Src src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{argument type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+}
+
+float instantiate_valid(unsigned char src) { return convert(src); }
+
+// expected-note@+1 {{in instantiation of function template specialization 
'convert<unsigned short>' requested here}}
+float instantiate_invalid(unsigned short src) { return convert(src); }
+
+template <typename Src>
+auto deduced_result(Src src)
+    -> decltype(__builtin_elementwise_convert_from_f8e5m2_f32(src)) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src);
+}
+
+static_assert(
+    __is_same(decltype(deduced_result((unsigned char)0)), float), "");
+
+using v4u8 = unsigned char __attribute__((ext_vector_type(4)));
+using v4f32 = float __attribute__((ext_vector_type(4)));
+static_assert(__is_same(decltype(deduced_result(v4u8{})), v4f32), "");
+
+void noexcept_check(unsigned char src) {
+  static_assert(
+      noexcept(__builtin_elementwise_convert_from_f8e5m2_f32(src)), "");
+}
+
+static_assert(
+    !__has_constexpr_builtin(
+        __builtin_elementwise_convert_from_f8e5m2_f32), "");
+
+constexpr float constant_evaluation_is_deferred =
+    __builtin_elementwise_convert_from_f8e5m2_f32(
+        (unsigned char)0); // expected-error@-1 {{constexpr variable 
'constant_evaluation_is_deferred' must be initialized by a constant expression}}
diff --git 
a/clang/test/SemaOpenCL/builtins-elementwise-convert-from-arbitrary-fp.cl 
b/clang/test/SemaOpenCL/builtins-elementwise-convert-from-arbitrary-fp.cl
new file mode 100644
index 0000000000000..386a8d890e041
--- /dev/null
+++ b/clang/test/SemaOpenCL/builtins-elementwise-convert-from-arbitrary-fp.cl
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple spir-unknown-unknown -x cl \
+// RUN:   -finclude-default-header -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+#if !__has_builtin(__builtin_elementwise_convert_from_f8e5m2_f32)
+#error "missing elementwise arbitrary FP conversion builtin"
+#endif
+
+#if __has_builtin(__builtin_elementwise_convert_from_f6e3m2fn_f32)
+#error "deferred arbitrary FP conversion builtin is unexpectedly available"
+#endif
+
+float convert_scalar(uchar src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src);
+}
+
+_Float16 convert_f16(uchar src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f16(src);
+}
+
+__bf16 convert_bf16(uchar src) {
+  return __builtin_elementwise_convert_from_f8e5m2_bf16(src);
+}
+
+float4 convert_vector(uchar4 src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src);
+}
+
+// f16 denotes _Float16 even in OpenCL; 'half' comes from the normal
+// conversion rules.
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+half convert_to_half(uchar src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f16(src);
+}
+
+half4 convert_to_half_vector(uchar4 src) {
+  return __builtin_elementwise_convert_from_f8e5m2_f16(src);
+}

>From 8847f812655a59cd33b5998e9766528b564b328e Mon Sep 17 00:00:00 2001
From: Chinmay Deshpande <[email protected]>
Date: Fri, 9 Oct 2026 16:20:49 -0400
Subject: [PATCH 2/2] Address review feedback on FP8 conversion builtins

Reuse err_builtin_invalid_arg_type for all source operand errors
instead of builtin-specific diagnostics.

Accept integer constants that fit the format width, such as 0x38,
and std::byte, so common byte values need no explicit cast.

Drop the unused OpenCL fp64 path from checkFloatingPointTypeSupport.

Document floating-point environment and fast-math behavior; trim
implementation detail from the user docs.

Change-Id: I8676a49540bdbbb8a90827c83764803eeea850a5
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
 clang/docs/LanguageExtensions.md              | 15 ++--
 .../clang/Basic/ArbitraryFPFormats.def        |  3 +-
 .../clang/Basic/DiagnosticSemaKinds.td        | 12 +---
 clang/lib/Sema/SemaChecking.cpp               | 70 ++++++++++++-------
 clang/lib/Sema/SemaType.cpp                   | 27 +++----
 ...ns-elementwise-convert-from-arbitrary-fp.c |  9 +++
 ...ementwise-convert-from-arbitrary-fp-neon.c |  4 +-
 ...lementwise-convert-from-arbitrary-fp-rvv.c |  2 +-
 ...ns-elementwise-convert-from-arbitrary-fp.c | 39 ++++++++---
 ...-elementwise-convert-from-arbitrary-fp.cpp | 25 ++++++-
 10 files changed, 133 insertions(+), 73 deletions(-)

diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index dfff19ee3bd93..690ddcf996440 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -3716,9 +3716,6 @@ The result is a scalar for a scalar input or a vector 
with the same number of el
 Supported vector kinds are GNU `vector_size` and Clang/OpenCL 
`ext_vector_type`.
 The result preserves which of those two vector kinds the input uses.
 Sizeless vectors and target-specific fixed-length vector kinds are rejected.
-Preserving both the lane count and a target-specific vector kind after widening
-the element type can produce an invalid type or ABI combination, such as a
-widened NEON vector.
 
 The source format suffix determines the interpretation and required integer 
element width:
 
@@ -3737,15 +3734,13 @@ The destination suffix determines the result element 
type:
 | `f32`  | `float`             |
 
 The `f16` suffix denotes `_Float16` in every language mode, including OpenCL.
-The three source suffixes and three destination suffixes form exactly nine
-builtin spellings.
 
 `Float8E5M3FNU` has no sign bit and no infinity encoding, and its exponent
 range exceeds that of `_Float16`. Its seven largest finite encodings therefore
 convert to infinity rather than exactly when the destination is `f16`; the
 `bf16` and `f32` destinations are exact.
 
-Only the signedness-free width of `bits` matters, so for an 8-bit format any 
8-bit `char`, `signed char`, `unsigned char`, or `_BitInt(8)` of either 
signedness may be used.
+Only the signedness-free width of `bits` matters, so for an 8-bit format any 
8-bit `char`, `signed char`, `unsigned char`, `_BitInt(8)` of either 
signedness, or `std::byte` may be used.
 On targets that have it, `__mfp8` is also accepted as a scalar source, because
 it is an opaque 8-bit floating-point container with no interpretation of its
 own. Its Neon vector types are rejected with the other target-specific vector
@@ -3753,11 +3748,13 @@ kinds.
 
 Integer promotions and the usual arithmetic conversions are not applied to
 `bits`, so an expression that C promotes to `int` needs an explicit cast back
-to an 8-bit container:
+to an 8-bit container. Integer constant expressions whose value fits in the
+format width, such as `0x38`, are accepted directly:
 
 ```c
 unsigned char b;
 __builtin_elementwise_convert_from_f8e5m2_f32((unsigned char)(b >> 1));
+__builtin_elementwise_convert_from_f8e5m2_f32(0x38);
 ```
 
 These builtins are available in C, C++, and OpenCL, but are not supported in 
constant expressions.
@@ -3765,6 +3762,10 @@ These builtins are available in C, C++, and OpenCL, but 
are not supported in con
 Each builtin maps to the `llvm.convert.from.arbitrary.fp` intrinsic; see its 
description in the LLVM Language Reference for the exact conversion semantics.
 NaN results follow LLVM's general NaN rules; the sign, quiet or signaling 
state,
 and payload are not guaranteed to be preserved.
+The conversion is exact or overflows to infinity, so the rounding mode has no
+effect on the result.
+As with other floating-point operations, `-ffinite-math-only` (implied by
+`-ffast-math`) makes the result undefined if it is a NaN or an infinity.
 Current generic code generation for the intrinsic is SelectionDAG-only.
 Other code-generation paths are future work.
 
diff --git a/clang/include/clang/Basic/ArbitraryFPFormats.def 
b/clang/include/clang/Basic/ArbitraryFPFormats.def
index a2696154d840e..977bd6a3155ae 100644
--- a/clang/include/clang/Basic/ArbitraryFPFormats.def
+++ b/clang/include/clang/Basic/ArbitraryFPFormats.def
@@ -15,7 +15,8 @@
 // be accepted by APFloat::getArbitraryFPSemantics, or lowering fails.
 //
 // The sub-byte encodings (Float6E3M2FN, Float6E2M3FN, Float4E2M1FN) lower but
-// are not exposed; Clang cannot spell their vector element types coherently.
+// are not exposed: _BitInt(6) vectors are rejected, and a _BitInt(4) vector's
+// sizeof disagrees with its bit-packed IR type.
 //
 
//===----------------------------------------------------------------------===//
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b458ecb4d4d82..3d573d9b58b9d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11485,16 +11485,6 @@ def err_builtin_non_vector_type : Error<
 def err_convertvector_incompatible_vector : Error<
   "first two arguments to __builtin_convertvector must have the same number of 
elements">;
 
-def err_arbitrary_fp_source_type : Error<
-  "argument of type %0 cannot hold an '%1' encoding; expected an integer of "
-  "exactly %2 bits, a vector of such integers, or __mfp8">;
-def err_arbitrary_fp_source_width : Error<
-  "%select{argument type|vector element type}0 %1 must be exactly %2 bits "
-  "wide to hold an '%3' encoding">;
-def err_arbitrary_fp_unsupported_vector : Error<
-  "argument of type %0 has an unsupported vector kind; only GNU "
-  "'vector_size' and Clang 'ext_vector_type' vectors are supported">;
-
 def err_first_argument_to_cwsc_not_call : Error<
   "first argument to __builtin_call_with_static_chain must be a non-member 
call expression">;
 def err_first_argument_to_cwsc_block_call : Error<
@@ -13449,7 +13439,7 @@ def err_builtin_invalid_arg_type: Error<
   "%plural{0:|: }1"
   // Second component: integer-like types
   "%select{|integer|signed integer|unsigned integer|'int'|"
-  "pointer to a valid matrix element|boolean}2"
+  "pointer to a valid matrix element|boolean|8-bit integer}2"
   // A space after a non-empty second component
   "%plural{0:|: }2"
   // An 'or' if non-empty second and third components are combined
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index a64576b2e7287..cbfdf30631e27 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3151,26 +3151,22 @@ static QualType getVectorElementType(ASTContext 
&Context, QualType VecTy) {
 }
 
 /// Decode a __builtin_elementwise_convert_from_<Src>_<Dst> builtin ID into its
-/// llvm.convert.from.arbitrary.fp interpretation, the source suffix as 
spelled,
-/// and the destination element type.
+/// llvm.convert.from.arbitrary.fp interpretation and destination element type.
 static bool getArbitraryFPConversion(ASTContext &Ctx, unsigned BuiltinID,
                                      StringRef &Interpretation,
-                                     StringRef &SrcSuffix, QualType &DstEltTy) 
{
+                                     QualType &DstEltTy) {
   switch (BuiltinID) {
 #define ARBITRARY_FP_FORMAT(Src, LLVMName)                                     
\
   case Builtin::BI__builtin_elementwise_convert_from_##Src##_f16:              
\
     Interpretation = LLVMName;                                                 
\
-    SrcSuffix = #Src;                                                          
\
     DstEltTy = Ctx.Float16Ty;                                                  
\
     return true;                                                               
\
   case Builtin::BI__builtin_elementwise_convert_from_##Src##_bf16:             
\
     Interpretation = LLVMName;                                                 
\
-    SrcSuffix = #Src;                                                          
\
     DstEltTy = Ctx.BFloat16Ty;                                                 
\
     return true;                                                               
\
   case Builtin::BI__builtin_elementwise_convert_from_##Src##_f32:              
\
     Interpretation = LLVMName;                                                 
\
-    SrcSuffix = #Src;                                                          
\
     DstEltTy = Ctx.FloatTy;                                                    
\
     return true;
 #include "clang/Basic/ArbitraryFPFormats.def"
@@ -3179,15 +3175,36 @@ static bool getArbitraryFPConversion(ASTContext &Ctx, 
unsigned BuiltinID,
   }
 }
 
+/// Narrow an integer constant such as 0x38 to \p FormatBits if its value fits.
+/// Returns true if it does not.
+static bool narrowFPBitsConstant(Sema &S, CallExpr *TheCall,
+                                 unsigned FormatBits) {
+  Expr *Src = TheCall->getArg(0);
+
+  // Recheck on instantiation.
+  if (Src->isValueDependent()) {
+    return false;
+  }
+
+  std::optional<llvm::APSInt> Val = Src->getIntegerConstantExpr(S.Context);
+  if (!Val || Val->isNegative() || Val->getActiveBits() > FormatBits) {
+    return true;
+  }
+
+  QualType FitTy =
+      S.Context.getIntTypeForBitwidth(FormatBits, /*Signed=*/false);
+  TheCall->setArg(0, S.ImpCastExprToType(Src, FitTy, CK_IntegralCast).get());
+  return false;
+}
+
 static bool BuiltinElementwiseConvertFromArbitraryFP(Sema &S, CallExpr 
*TheCall,
                                                      unsigned BuiltinID) {
   if (S.checkArgCount(TheCall, 1))
     return true;
 
-  StringRef Interpretation, SrcSuffix;
+  StringRef Interpretation;
   QualType DstEltTy;
-  if (!getArbitraryFPConversion(S.Context, BuiltinID, Interpretation, 
SrcSuffix,
-                                DstEltTy))
+  if (!getArbitraryFPConversion(S.Context, BuiltinID, Interpretation, 
DstEltTy))
     llvm_unreachable("builtin is missing from ArbitraryFPFormats.def");
 
   if (S.checkFloatingPointTypeSupport(DstEltTy, TheCall->getBeginLoc(),
@@ -3219,21 +3236,26 @@ static bool 
BuiltinElementwiseConvertFromArbitraryFP(Sema &S, CallExpr *TheCall,
   const auto *SrcVecTy = SrcTy->getAs<VectorType>();
   QualType SrcEltTy = SrcVecTy ? SrcVecTy->getElementType() : SrcTy;
 
-  if (SrcTy->isSizelessVectorType() ||
-      (SrcVecTy && !SrcTy->isExtVectorType() &&
-       SrcVecTy->getVectorKind() != VectorKind::Generic))
-    return S.Diag(Src->getBeginLoc(), 
diag::err_arbitrary_fp_unsupported_vector)
-           << SrcTy << Src->getSourceRange();
-
-  if (!SrcEltTy->isIntegerType() || SrcEltTy->isBooleanType() ||
-      SrcEltTy->isEnumeralType())
-    return S.Diag(Src->getBeginLoc(), diag::err_arbitrary_fp_source_type)
-           << SrcTy << SrcSuffix << FormatBits << Src->getSourceRange();
-
-  if (S.Context.getIntWidth(SrcEltTy) != FormatBits)
-    return S.Diag(Src->getBeginLoc(), diag::err_arbitrary_fp_source_width)
-           << (SrcVecTy != nullptr) << SrcEltTy << FormatBits << SrcSuffix
-           << Src->getSourceRange();
+  auto DiagInvalidSrc = [&] {
+    return S.Diag(Src->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+           << /*ordinal=*/1 << /*scalar or vector*/ 5 << /*8-bit integer*/ 7
+           << /*no fp*/ 0 << SrcTy << Src->getSourceRange();
+  };
+
+  bool IsVendorVector = SrcVecTy && !SrcTy->isExtVectorType() &&
+                        SrcVecTy->getVectorKind() != VectorKind::Generic;
+  // std::byte is the C++ byte container; other enums are rejected.
+  bool IsIntElt = SrcEltTy->isStdByteType() ||
+                  (SrcEltTy->isIntegerType() && !SrcEltTy->isBooleanType() &&
+                   !SrcEltTy->isEnumeralType());
+  if (SrcTy->isSizelessVectorType() || IsVendorVector || !IsIntElt) {
+    return DiagInvalidSrc();
+  }
+
+  if (S.Context.getIntWidth(SrcEltTy) != FormatBits &&
+      (SrcVecTy || narrowFPBitsConstant(S, TheCall, FormatBits))) {
+    return DiagInvalidSrc();
+  }
 
   QualType DstTy = DstEltTy;
   if (SrcVecTy)
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 03713d90d6799..f3a05c5aced17 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -922,24 +922,8 @@ bool Sema::checkFloatingPointTypeSupport(QualType Ty, 
SourceLocation Loc,
       if (DiagnoseTarget)
         return targetDiag(Loc, diag::err_type_unsupported) << "__bf16";
     }
-    return false;
   }
 
-  if (!getLangOpts().OpenCL ||
-      (Ty != Context.DoubleTy && Ty != Context.LongDoubleTy))
-    return false;
-
-  if (!getOpenCLOptions().isSupported("cl_khr_fp64", getLangOpts())) {
-    Diag(Loc, diag::err_opencl_requires_extension)
-        << 0 << Ty
-        << (getLangOpts().getOpenCLCompatibleVersion() >= 300
-                ? "cl_khr_fp64 and __opencl_c_fp64"
-                : "cl_khr_fp64");
-    return true;
-  }
-
-  if (!getOpenCLOptions().isAvailableOption("cl_khr_fp64", getLangOpts()))
-    Diag(Loc, diag::ext_opencl_double_without_pragma);
   return false;
 }
 
@@ -1222,7 +1206,16 @@ static QualType 
ConvertDeclSpecToType(TypeProcessingState &state) {
       Result = Context.LongDoubleTy;
     else
       Result = Context.DoubleTy;
-    S.checkFloatingPointTypeSupport(Result, DS.getTypeSpecTypeLoc());
+    if (S.getLangOpts().OpenCL) {
+      if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
+        S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
+            << 0 << Result
+            << (S.getLangOpts().getOpenCLCompatibleVersion() >= 300
+                    ? "cl_khr_fp64 and __opencl_c_fp64"
+                    : "cl_khr_fp64");
+      else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", 
S.getLangOpts()))
+        S.Diag(DS.getTypeSpecTypeLoc(), 
diag::ext_opencl_double_without_pragma);
+    }
     break;
   case DeclSpec::TST_float128:
     if (!S.Context.getTargetInfo().hasFloat128Type() &&
diff --git 
a/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c 
b/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
index 01289993d5d6e..3db6b3311f2a1 100644
--- a/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
+++ b/clang/test/CodeGen/builtins-elementwise-convert-from-arbitrary-fp.c
@@ -170,3 +170,12 @@ g4f32 from_g4f8e5m2(g4u8 b) {
   return __builtin_elementwise_convert_from_f8e5m2_f32(b);
 }
 
+// CHECK-LABEL: define dso_local float @from_constant_f8e5m2(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call float 
@llvm.convert.from.arbitrary.fp.f32.i8(i8 56, metadata !"Float8E5M2")
+// CHECK-NEXT:    ret float [[TMP0]]
+//
+float from_constant_f8e5m2(void) {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(0x38);
+}
diff --git 
a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
index ee2a92c3e385d..6bf6a4b593ef8 100644
--- a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-neon.c
@@ -5,7 +5,7 @@ typedef unsigned char uint8x8_t 
__attribute__((neon_vector_type(8)));
 typedef __mfp8 mfloat8x8_t __attribute__((neon_vector_type(8)));
 
 void test_neon_vector(uint8x8_t src) {
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 
'uint8x8_t'}}
 }
 
 // __mfp8 is an opaque 8-bit container, so it is accepted for the 8-bit
@@ -19,5 +19,5 @@ void test_mfp8_scalar(__mfp8 src) {
 }
 
 void test_mfp8_vector(mfloat8x8_t src) {
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 
'mfloat8x8_t'}}
 }
diff --git 
a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
index 7124e55e075af..f0e8c656e59ae 100644
--- a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp-rvv.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple riscv64 -target-feature +v -fsyntax-only -verify %s
 
 __rvv_float32m1_t convert(__rvv_uint8m1_t src) {
-  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{has an unsupported vector kind}}
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 
'__rvv_uint8m1_t')}}
 }
diff --git a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c 
b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
index 2c60d7356ecd4..8b52b2cbbdc9c 100644
--- a/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
+++ b/clang/test/Sema/builtins-elementwise-convert-from-arbitrary-fp.c
@@ -104,7 +104,28 @@ void test_source_formats(unsigned char b) {
 // Integer promotions do not apply to the source.
 void test_no_promotion(unsigned char b) {
   (void)__builtin_elementwise_convert_from_f8e5m2_f32((unsigned char)(b >> 1));
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b >> 1); // 
expected-error {{argument type 'int' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b >> 1); // 
expected-error {{1st argument must be a scalar or vector of 8-bit integer types 
(was 'int')}}
+}
+
+// Integer constant expressions are accepted if the value fits in 8 bits.
+void test_constant(int i) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(0x38);
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(0xFF);
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32('a');
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(0x100); // 
expected-error {{1st argument must be a scalar or vector of 8-bit integer types 
(was 'int')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(-1); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'int')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(i); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'int')}}
+}
+
+struct bit_fields {
+  unsigned u : 8;
+  unsigned char c : 8;
+};
+
+// Bit-field width is not part of the type.
+void test_bit_fields(struct bit_fields s) {
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(s.c);
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(s.u); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'unsigned 
int')}}
 }
 
 void test_arity(unsigned char b) {
@@ -113,20 +134,20 @@ void test_arity(unsigned char b) {
 }
 
 void test_width(unsigned short b16, unsigned _BitInt(4) b4, v4u16 vb16) {
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b16); // expected-error 
{{argument type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b4); // expected-error 
{{argument type 'unsigned _BitInt(4)' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb16); // expected-error 
{{vector element type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b16); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'unsigned 
short')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b4); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'unsigned 
_BitInt(4)')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb16); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'v4u16' 
(vector of 4 'unsigned short' values))}}
 }
 
 void test_operand_types(float f, void *p) {
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(f); // expected-error 
{{argument of type 'float' cannot hold an 'f8e5m2' encoding; expected an 
integer of exactly 8 bits, a vector of such integers, or __mfp8}}
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(p); // expected-error 
{{argument of type 'void *' cannot hold an 'f8e5m2' encoding; expected an 
integer of exactly 8 bits, a vector of such integers, or __mfp8}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(f); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'float')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(p); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'void 
*')}}
 }
 
 void test_disallowed_integer_types(_Bool b, enum byte_enum e, v4bool vb) {
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b); // expected-error 
{{argument of type '_Bool' cannot hold an 'f8e5m2' encoding}}
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(e); // expected-error 
{{argument of type 'enum byte_enum' cannot hold an 'f8e5m2' encoding}}
-  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb); // expected-error 
{{cannot hold an 'f8e5m2' encoding}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(b); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was '_Bool')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(e); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'enum 
byte_enum')}}
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(vb); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'v4bool'}}
 }
 
 void test_volatile_source(volatile unsigned char *b) {
diff --git 
a/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp 
b/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
index 8e16ad41cc850..4d0bff33f2644 100644
--- a/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
+++ b/clang/test/SemaCXX/builtins-elementwise-convert-from-arbitrary-fp.cpp
@@ -2,7 +2,7 @@
 // RUN:   -fsyntax-only -verify %s
 
 template <typename Src> float convert(Src src) {
-  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{argument type 'unsigned short' must be exactly 8 bits wide to hold an 
'f8e5m2' encoding}}
+  return __builtin_elementwise_convert_from_f8e5m2_f32(src); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'unsigned 
short')}}
 }
 
 float instantiate_valid(unsigned char src) { return convert(src); }
@@ -23,6 +23,29 @@ using v4u8 = unsigned char 
__attribute__((ext_vector_type(4)));
 using v4f32 = float __attribute__((ext_vector_type(4)));
 static_assert(__is_same(decltype(deduced_result(v4u8{})), v4f32), "");
 
+template <int N> float convert_constant() {
+  return __builtin_elementwise_convert_from_f8e5m2_f32(N); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 'int')}}
+}
+
+float instantiate_constant() { return convert_constant<0x38>(); }
+
+// expected-note@+1 {{in instantiation of function template specialization 
'convert_constant<256>' requested here}}
+float instantiate_constant_invalid() { return convert_constant<0x100>(); }
+
+namespace std {
+enum class byte : unsigned char {};
+} // namespace std
+
+enum class other_byte : unsigned char {};
+
+void test_byte(std::byte b, other_byte o) {
+  static_assert(
+      __is_same(decltype(__builtin_elementwise_convert_from_f8e5m2_f32(b)),
+                float),
+      "");
+  (void)__builtin_elementwise_convert_from_f8e5m2_f32(o); // expected-error 
{{1st argument must be a scalar or vector of 8-bit integer types (was 
'other_byte')}}
+}
+
 void noexcept_check(unsigned char src) {
   static_assert(
       noexcept(__builtin_elementwise_convert_from_f8e5m2_f32(src)), "");

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to