[flang-commits] [flang] [mlir] [mlir] Support human-readable float literals in the textual IR (PR #210422)

Victor Perez via flang-commits flang-commits at lists.llvm.org
Fri Jul 24 12:56:48 PDT 2026


https://github.com/victor-eds updated https://github.com/llvm/llvm-project/pull/210422

>From 5971da3896e830c9242b1f73fa7d64a5fa39cb95 Mon Sep 17 00:00:00 2001
From: Victor Perez <victor.pc.upm at gmail.com>
Date: Fri, 17 Jul 2026 11:52:35 -0700
Subject: [PATCH] [mlir] Support human-readable float literals in the textual
 IR

Add LLVM-style textual floating-point literals to the MLIR assembly
format, both parsed and printed:

  +inf / -inf
  +qnan / -qnan
  +nan(0x<payload>) / +snan(0x<payload>)   (and their negatives)
  0x1.8p3                                   (C-style hexadecimal float)

The sign is mandatory for inf/NaN, so bare `inf`/`nan` remain ordinary
identifiers. C-style hex floats are distinguished from the existing
bit-pattern form by a fractional part and/or a binary exponent; the plain
`0x..` form is still parsed as a bit pattern.

Float literal values are now built directly in the target type's
semantics: Token::getFloatingPointValue takes the target fltSemantics
(and sign) and returns std::optional<APFloat> via
APFloat::convertFromString, instead of first converting to double. This
preserves NaN payloads and fixes a precision bug for types wider than
double: e.g. `0.1 : f128` was previously stored as the double
approximation of 0.1 widened to f128 rather than the correctly-rounded
f128 value. convertFromString accepts inf/nan/snan spellings but not
"qnan" (built via APFloat::getQNaN) nor a leading '+', so the sign is
handled explicitly. The printer mirrors LLVM's writeAPFloatInternal.

A special value that the target type cannot represent is now a parse
error rather than an APFloat abort: the parser rejects infinity, NaN, or
a negative value when the type's semantics lack the matching property
(e.g. `+inf` for a type without infinity, or `-...` for an unsigned
type).

The printer emits the human-readable form by default. The
--mlir-print-float-special-literals-as-hex flag restores the legacy
output, where infinities and NaNs print as a hexadecimal bit pattern.
The parser accepts both forms regardless of the flag. The flag is wired
into every tool that registers the AsmPrinter command-line options
(mlir-opt, mlir-translate, and flang's bbc).

Also thread the float literal's location into the FloatAttr parse
diagnostics so "not valid for specified type" points at the constant
rather than the following token.

Signed-off-by: Victor Perez <victor.pc.upm at gmail.com>
---
 flang/test/Transforms/simplifyintrinsics.fir  |   4 +-
 mlir/docs/LangRef.md                          |  16 +++
 mlir/include/mlir/IR/OperationSupport.h       |  11 ++
 mlir/lib/AsmParser/AttributeParser.cpp        |  21 ++--
 mlir/lib/AsmParser/Lexer.cpp                  |  64 ++++++++++
 mlir/lib/AsmParser/Lexer.h                    |   1 +
 mlir/lib/AsmParser/Parser.cpp                 |  11 +-
 mlir/lib/AsmParser/Token.cpp                  |  55 +++++++-
 mlir/lib/AsmParser/Token.h                    |  11 +-
 mlir/lib/IR/AsmPrinter.cpp                    |  90 +++++++++++---
 .../8-bit-float-saturation-ocp.mlir           |   8 +-
 .../ArithToAMDGPU/8-bit-float-saturation.mlir |   8 +-
 .../ComplexToLLVM/complex-range-option.mlir   |   4 +-
 .../ComplexToSPIRV/complex-to-spirv.mlir      |   2 +-
 .../complex-range-option.mlir                 |   4 +-
 .../convert-to-standard.mlir                  |  44 +++----
 .../GPUToNVVM/wmma-ops-to-nvvm.mlir           |   8 +-
 .../TosaToLinalg/tosa-to-linalg.mlir          |  16 +--
 .../vector-reduction-to-llvm.mlir             |   6 +-
 .../SuperVectorize/vectorize_reduction.mlir   |  12 +-
 mlir/test/Dialect/Arith/emulate-wide-int.mlir |   2 +-
 mlir/test/Dialect/Builtin/Bytecode/attrs.mlir |  10 +-
 .../Builtin/Bytecode/builtin_fixed.mlir       |   4 +-
 .../Builtin/Bytecode/builtin_fixed_0.mlirbc   | Bin 5470 -> 5470 bytes
 mlir/test/Dialect/Complex/canonicalize.mlir   |   6 +-
 .../Linalg/transform-op-decompose.mlir        |   2 +-
 .../Linalg/transform-op-split-reduction.mlir  |   8 +-
 .../Linalg/transform-tile-reduction.mlir      |   2 +-
 mlir/test/Dialect/Math/canonicalize.mlir      |   4 +-
 mlir/test/Dialect/Math/expand-math.mlir       |   8 +-
 .../Math/polynomial-approximation.mlir        |  18 +--
 mlir/test/Dialect/SPIRV/IR/structure-ops.mlir |   2 +-
 .../Tosa/constant-reciprocal-fold.mlir        |  14 +--
 mlir/test/Dialect/Tosa/invalid.mlir           |   4 +-
 mlir/test/Dialect/XeGPU/propagate-layout.mlir |   2 +-
 mlir/test/IR/array-of-attr.mlir               |   2 +-
 mlir/test/IR/custom-float-attr-roundtrip.mlir |   6 +-
 mlir/test/IR/float-literals-hex.mlir          |  50 ++++++++
 mlir/test/IR/float-literals.mlir              | 117 ++++++++++++++++++
 mlir/test/IR/invalid-builtin-attributes.mlir  |  95 ++++++++++++++
 mlir/test/IR/parser.mlir                      |  66 +++++-----
 41 files changed, 637 insertions(+), 181 deletions(-)
 create mode 100644 mlir/test/IR/float-literals-hex.mlir
 create mode 100644 mlir/test/IR/float-literals.mlir

diff --git a/flang/test/Transforms/simplifyintrinsics.fir b/flang/test/Transforms/simplifyintrinsics.fir
index 1cfda08e39694..585083df690c5 100644
--- a/flang/test/Transforms/simplifyintrinsics.fir
+++ b/flang/test/Transforms/simplifyintrinsics.fir
@@ -2005,7 +2005,7 @@ func.func @_QPtestminloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
 // CHECK:             %[[FLAG_SET:.*]] = arith.constant 1 : i32
 // CHECK:             %[[FLAG_EMPTY:.*]] = arith.constant 0 : i32
 // CHECK:             fir.store %[[FLAG_EMPTY]] to %[[FLAG_ALLOC]] : !fir.ref<i32>
-// CHECK:             %[[MAX:.*]] = arith.constant 0x7FF0000000000000 : f64
+// CHECK:             %[[MAX:.*]] = arith.constant +inf : f64
 // CHECK:             %[[C_INDEX1:.*]] = arith.constant 1 : index
 // CHECK:             %[[DIM_INDEX:.*]] = arith.constant 0 : index
 // CHECK:             %[[DIMS:.*]]:3 = fir.box_dims %[[BOX_INARR]], %[[DIM_INDEX]] : (!fir.box<!fir.array<?xf64>>, index) -> (index, index, index)
@@ -2581,7 +2581,7 @@ func.func @_QPtestmaxloc_works1d_scalarmask_f64(%arg0: !fir.ref<!fir.array<10xf6
 // CHECK:             %[[FLAG_SET:.*]] = arith.constant 1 : i32
 // CHECK:             %[[FLAG_EMPTY:.*]] = arith.constant 0 : i32
 // CHECK:             fir.store %[[FLAG_EMPTY]] to %[[FLAG_ALLOC]] : !fir.ref<i32>
-// CHECK:             %[[MAX:.*]] = arith.constant 0xFFF0000000000000 : f64
+// CHECK:             %[[MAX:.*]] = arith.constant -inf : f64
 // CHECK:             %[[C_INDEX1:.*]] = arith.constant 1 : index
 // CHECK:             %[[DIM_INDEX:.*]] = arith.constant 0 : index
 // CHECK:             %[[DIMS:.*]]:3 = fir.box_dims %[[BOX_INARR]], %[[DIM_INDEX]] : (!fir.box<!fir.array<?xf64>>, index) -> (index, index, index)
diff --git a/mlir/docs/LangRef.md b/mlir/docs/LangRef.md
index fea34c093418d..2ba81375a6ac4 100644
--- a/mlir/docs/LangRef.md
+++ b/mlir/docs/LangRef.md
@@ -174,9 +174,25 @@ integer-literal ::= decimal-literal | hexadecimal-literal
 decimal-literal ::= digit+
 hexadecimal-literal ::= `0x` hex_digit+
 float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
+                | `0x` hex_digit+ (`.` hex_digit*)? [pP] [-+]? digit+
+                | float-special-literal
+float-special-literal ::= [-+] (`inf` | `qnan` | `s`? `nan` `(` `0x` hex_digit+ `)`)
 string-literal  ::= `"` [^"\n\f\v\r]* `"`   TODO: define escaping rules
 ```
 
+Special floating point values are spelled with a mandatory sign: `+inf`/`-inf`
+for infinities, `+qnan`/`-qnan` for the preferred quiet NaN, and
+`+nan(0x..)`/`+snan(0x..)` for quiet/signaling NaNs with an explicit hexadecimal
+payload. Finite values may also be written as C-style hexadecimal floats
+(`0x1.8p3`). The `0x` bit-pattern form without a fractional part or exponent
+(e.g. `0x7F800000`) is instead interpreted as the raw bit pattern of the target
+type.
+
+The `--mlir-print-float-special-literals-as-hex` flag makes the printer emit infinities
+and NaNs as a `0x` bit pattern instead of the human-readable form. This restores
+the legacy output for backwards compatibility. The parser accepts both forms
+regardless of the flag.
+
 Not listed here, but MLIR does support comments. They use standard BCPL syntax,
 starting with a `//` and going until the end of the line.
 
diff --git a/mlir/include/mlir/IR/OperationSupport.h b/mlir/include/mlir/IR/OperationSupport.h
index 942b55e8f7a76..64f9ecfa2f1d7 100644
--- a/mlir/include/mlir/IR/OperationSupport.h
+++ b/mlir/include/mlir/IR/OperationSupport.h
@@ -1239,6 +1239,10 @@ class OpPrintingFlags {
   /// Print SSA IDs using their NameLoc, if provided, as prefix.
   OpPrintingFlags &printNameLocAsPrefix(bool enable = true);
 
+  /// Print special float literals (inf, NaN) as a hexadecimal bit pattern
+  /// instead of the human-readable form. Restores the legacy output.
+  OpPrintingFlags &printFloatSpecialLiteralsAsHex(bool enable = true);
+
   /// Return if the given ElementsAttr should be elided.
   bool shouldElideElementsAttr(ElementsAttr attr) const;
 
@@ -1282,6 +1286,10 @@ class OpPrintingFlags {
   /// IDs
   bool shouldUseNameLocAsPrefix() const;
 
+  /// Return if special float literals (inf, NaN) should print as a hexadecimal
+  /// bit pattern.
+  bool shouldPrintFloatSpecialLiteralsAsHex() const;
+
 private:
   /// Elide large elements attributes if the number of elements is larger than
   /// the upper limit.
@@ -1318,6 +1326,9 @@ class OpPrintingFlags {
 
   /// Print SSA IDs using NameLocs as prefixes
   bool useNameLocAsPrefix : 1;
+
+  /// Print special float literals (inf, NaN) as a hexadecimal bit pattern.
+  bool printFloatSpecialLiteralsAsHexFlag : 1;
 };
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/AsmParser/AttributeParser.cpp b/mlir/lib/AsmParser/AttributeParser.cpp
index ca8e4ae2cecbc..5f7ae4aa8bdc6 100644
--- a/mlir/lib/AsmParser/AttributeParser.cpp
+++ b/mlir/lib/AsmParser/AttributeParser.cpp
@@ -339,9 +339,8 @@ ParseResult Parser::parseAttributeDict(NamedAttrList &attributes) {
 
 /// Parse a float attribute.
 Attribute Parser::parseFloatAttr(Type type, bool isNegative) {
-  auto val = getToken().getFloatingPointValue();
-  if (!val)
-    return (emitError("floating point value too large for attribute"), nullptr);
+  Token tok = getToken();
+  SMLoc loc = tok.getLoc();
   consumeToken(Token::floatliteral);
   if (!type) {
     // Default to F64 when no type is specified.
@@ -350,10 +349,18 @@ Attribute Parser::parseFloatAttr(Type type, bool isNegative) {
     else if (!(type = parseType()))
       return nullptr;
   }
-  if (!isa<FloatType>(type))
-    return (emitError("floating point value not valid for specified type"),
-            nullptr);
-  return FloatAttr::get(type, isNegative ? -*val : *val);
+  auto floatType = dyn_cast<FloatType>(type);
+  if (!floatType) {
+    emitError(loc, "floating point value not valid for specified type");
+    return nullptr;
+  }
+
+  std::optional<APFloat> result =
+      tok.getFloatingPointValue(isNegative, floatType.getFloatSemantics(),
+                                [&] { return emitError(loc); });
+  if (!result)
+    return nullptr;
+  return FloatAttr::get(floatType, *result);
 }
 
 /// Construct an APint from a parsed value, a known attribute type and
diff --git a/mlir/lib/AsmParser/Lexer.cpp b/mlir/lib/AsmParser/Lexer.cpp
index 161dcb4ca27c0..3191b9e2b1d92 100644
--- a/mlir/lib/AsmParser/Lexer.cpp
+++ b/mlir/lib/AsmParser/Lexer.cpp
@@ -147,6 +147,9 @@ Token Lexer::lexToken() {
       return formToken(Token::equal, tokStart);
 
     case '+':
+      if (std::optional<Token> tok = lexSpecialFloatLiteral(
+              StringRef(tokStart, curBuffer.end() - tokStart)))
+        return *tok;
       return formToken(Token::plus, tokStart);
     case '*':
       return formToken(Token::star, tokStart);
@@ -155,6 +158,9 @@ Token Lexer::lexToken() {
         ++curPtr;
         return formToken(Token::arrow, tokStart);
       }
+      if (std::optional<Token> tok = lexSpecialFloatLiteral(
+              StringRef(tokStart, curBuffer.end() - tokStart)))
+        return *tok;
       return formToken(Token::minus, tokStart);
 
     case '?':
@@ -308,10 +314,46 @@ Token Lexer::lexEllipsis(const char *tokStart) {
   return formToken(Token::ellipsis, tokStart);
 }
 
+/// Try to lex a signed special float literal (inf/NaN) from `fromSign`, which
+/// starts at the already-consumed sign. On success returns a `floatliteral`
+/// (or `error`) token and advances `curPtr`, else std::nullopt (curPtr intact).
+///
+///   float-special ::= [-+] (`inf` | `qnan` | `s`? `nan(0x` hex_digit+ `)`)
+///
+std::optional<Token> Lexer::lexSpecialFloatLiteral(StringRef fromSign) {
+  const char *tokStart = fromSign.data();
+  StringRef afterSign = fromSign.drop_front();
+  StringRef keyword = afterSign.take_while(llvm::isAlpha);
+  StringRef rest = afterSign.drop_front(keyword.size());
+
+  // Reject `inf`/`qnan` that is only a prefix of a longer identifier.
+  if (keyword == "inf" || keyword == "qnan") {
+    if (!rest.empty() && (llvm::isAlnum(rest.front()) || rest.front() == '_' ||
+                          rest.front() == '$' || rest.front() == '.'))
+      return std::nullopt;
+    curPtr = rest.data();
+    return formToken(Token::floatliteral, tokStart);
+  }
+
+  // `nan(0x..)` / `snan(0x..)`: capture through ')'; APFloat validates later.
+  if ((keyword == "nan" || keyword == "snan") && rest.consume_front("(")) {
+    StringRef payload = rest.take_until([](char c) { return c == ')'; });
+    if (payload.end() == rest.end()) {
+      curPtr = afterSign.end();
+      return emitError(tokStart, "expected ')' in NaN literal");
+    }
+    curPtr = payload.end() + 1;
+    return formToken(Token::floatliteral, tokStart);
+  }
+
+  return std::nullopt;
+}
+
 /// Lex a number literal.
 ///
 ///   integer-literal ::= digit+ | `0x` hex_digit+
 ///   float-literal ::= [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
+///                    | `0x` hex_digit+ (`.` hex_digit*)? [pP] [-+]? digit+
 ///
 Token Lexer::lexNumber(const char *tokStart) {
   assert(isdigit(curPtr[-1]));
@@ -327,6 +369,28 @@ Token Lexer::lexNumber(const char *tokStart) {
     while (isxdigit(*curPtr))
       ++curPtr;
 
+    // C-style hex float (`0x1.fp13`): a '.'/'p' distinguishes it from the
+    // bit-pattern form; the binary exponent is mandatory.
+    if (*curPtr == '.' || *curPtr == 'p' || *curPtr == 'P') {
+      if (*curPtr == '.') {
+        ++curPtr;
+        while (isxdigit(*curPtr))
+          ++curPtr;
+      }
+      if (*curPtr != 'p' && *curPtr != 'P')
+        return emitError(tokStart, "expected binary exponent in hexadecimal "
+                                   "floating point literal");
+      ++curPtr;
+      if (*curPtr == '-' || *curPtr == '+')
+        ++curPtr;
+      if (!isdigit(static_cast<unsigned char>(*curPtr)))
+        return emitError(tokStart, "expected binary exponent in hexadecimal "
+                                   "floating point literal");
+      while (isdigit(*curPtr))
+        ++curPtr;
+      return formToken(Token::floatliteral, tokStart);
+    }
+
     return formToken(Token::integer, tokStart);
   }
 
diff --git a/mlir/lib/AsmParser/Lexer.h b/mlir/lib/AsmParser/Lexer.h
index 670444eb1f5b4..802ebcb7a8393 100644
--- a/mlir/lib/AsmParser/Lexer.h
+++ b/mlir/lib/AsmParser/Lexer.h
@@ -60,6 +60,7 @@ class Lexer {
   Token lexBareIdentifierOrKeyword(const char *tokStart);
   Token lexEllipsis(const char *tokStart);
   Token lexNumber(const char *tokStart);
+  std::optional<Token> lexSpecialFloatLiteral(StringRef fromSign);
   Token lexPrefixedIdentifier(const char *tokStart);
   Token lexString(const char *tokStart);
 
diff --git a/mlir/lib/AsmParser/Parser.cpp b/mlir/lib/AsmParser/Parser.cpp
index 952d7e460c6e2..d9173a5308eee 100644
--- a/mlir/lib/AsmParser/Parser.cpp
+++ b/mlir/lib/AsmParser/Parser.cpp
@@ -401,14 +401,9 @@ ParseResult Parser::parseFloatFromLiteral(std::optional<APFloat> &result,
                                           const llvm::fltSemantics &semantics) {
   // Check for a floating point value.
   if (tok.is(Token::floatliteral)) {
-    auto val = tok.getFloatingPointValue();
-    if (!val)
-      return emitError(tok.getLoc()) << "floating point value too large";
-
-    result.emplace(isNegative ? -*val : *val);
-    bool unused;
-    result->convert(semantics, APFloat::rmNearestTiesToEven, &unused);
-    return success();
+    result = tok.getFloatingPointValue(isNegative, semantics,
+                                       [&] { return emitError(tok.getLoc()); });
+    return failure(!result);
   }
 
   // Check for a hexadecimal float value.
diff --git a/mlir/lib/AsmParser/Token.cpp b/mlir/lib/AsmParser/Token.cpp
index 5bf25bac6a5c6..835cd892c9a19 100644
--- a/mlir/lib/AsmParser/Token.cpp
+++ b/mlir/lib/AsmParser/Token.cpp
@@ -11,8 +11,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "Token.h"
+#include "mlir/IR/Diagnostics.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <cassert>
 #include <cstdint>
@@ -51,12 +53,55 @@ std::optional<uint64_t> Token::getUInt64IntegerValue(StringRef spelling) {
   return result;
 }
 
-/// For a floatliteral, return its value as a double. Return std::nullopt if the
-/// value underflows or overflows.
-std::optional<double> Token::getFloatingPointValue() const {
-  double result = 0;
-  if (spelling.getAsDouble(result))
+/// For a floatliteral token, build its value in `semantics`, combining any sign
+/// folded into the spelling with `isNegative`. On failure, emits a diagnostic
+/// through `emitError` and returns std::nullopt.
+std::optional<APFloat> Token::getFloatingPointValue(
+    bool isNegative, const llvm::fltSemantics &semantics,
+    function_ref<InFlightDiagnostic()> emitError) const {
+  // The sign is either a preceding '-' token (isNegative) or folded into an
+  // inf/NaN spelling; both at once (e.g. `-+inf`) is invalid. Drop a leading
+  // '+' since convertFromString rejects it on NaN forms.
+  StringRef str = spelling;
+  if (isNegative && (str.starts_with("+") || str.starts_with("-"))) {
+    emitError() << "floating point literal has more than one sign";
     return std::nullopt;
+  }
+  bool isNeg = isNegative || str.consume_front("-");
+  str.consume_front("+");
+
+  // Reject values the type cannot represent; APFloat would otherwise abort.
+  if (isNeg && !APFloat::semanticsHasSignedRepr(semantics)) {
+    emitError() << "floating point type does not support negative values";
+    return std::nullopt;
+  }
+  if (str == "inf" && !APFloat::semanticsHasInf(semantics)) {
+    emitError() << "floating point type does not support infinity";
+    return std::nullopt;
+  }
+  bool wantsNaN =
+      str == "qnan" || str.starts_with("nan") || str.starts_with("snan");
+  if (wantsNaN && !APFloat::semanticsHasNaN(semantics)) {
+    emitError() << "floating point type does not support NaN";
+    return std::nullopt;
+  }
+
+  // convertFromString does not accept "qnan".
+  if (str == "qnan")
+    return APFloat::getQNaN(semantics, isNeg);
+
+  // Build in the target semantics to preserve NaN payloads; overflow/underflow
+  // are tolerated (inf/zero).
+  APFloat result(semantics);
+  llvm::Expected<APFloat::opStatus> status =
+      result.convertFromString(str, APFloat::rmNearestTiesToEven);
+  if (!status) {
+    llvm::consumeError(status.takeError());
+    emitError() << "invalid floating point literal";
+    return std::nullopt;
+  }
+  if (isNeg)
+    result.changeSign();
   return result;
 }
 
diff --git a/mlir/lib/AsmParser/Token.h b/mlir/lib/AsmParser/Token.h
index 9cae80fd51da0..9193465af9419 100644
--- a/mlir/lib/AsmParser/Token.h
+++ b/mlir/lib/AsmParser/Token.h
@@ -10,11 +10,13 @@
 #define MLIR_LIB_PARSER_TOKEN_H
 
 #include "mlir/Support/LLVM.h"
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/SMLoc.h"
 #include <optional>
 
 namespace mlir {
+class InFlightDiagnostic;
 
 /// This represents a token in the MLIR syntax.
 class Token {
@@ -84,9 +86,12 @@ class Token {
     return getUInt64IntegerValue(getSpelling());
   }
 
-  /// For a floatliteral token, return its value as a double. Returns
-  /// std::nullopt in the case of underflow or overflow.
-  std::optional<double> getFloatingPointValue() const;
+  /// For a floatliteral token, build its value in `semantics`, combining any
+  /// sign folded into the spelling with `isNegative`. On failure, emits a
+  /// diagnostic through `emitError` and returns std::nullopt.
+  std::optional<APFloat>
+  getFloatingPointValue(bool isNegative, const llvm::fltSemantics &semantics,
+                        function_ref<InFlightDiagnostic()> emitError) const;
 
   /// For an inttype token, return its bitwidth.
   std::optional<unsigned> getIntTypeBitwidth() const;
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index ca5c2d2a88ee5..b1f91a5d6f261 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -201,6 +201,11 @@ struct AsmPrinterOptions {
   llvm::cl::opt<bool> useNameLocAsPrefix{
       "mlir-use-nameloc-as-prefix", llvm::cl::init(false),
       llvm::cl::desc("Print SSA IDs using NameLocs as prefixes")};
+
+  llvm::cl::opt<bool> printFloatSpecialLiteralsAsHexOpt{
+      "mlir-print-float-special-literals-as-hex", llvm::cl::init(false),
+      llvm::cl::desc("Print special float literals (inf, NaN) as a hexadecimal "
+                     "bit pattern instead of the human-readable form")};
 };
 } // namespace
 
@@ -219,7 +224,7 @@ OpPrintingFlags::OpPrintingFlags()
       printGenericOpFormFlag(false), skipRegionsFlag(false),
       assumeVerifiedFlag(false), printLocalScope(false),
       printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
-      useNameLocAsPrefix(false) {
+      useNameLocAsPrefix(false), printFloatSpecialLiteralsAsHexFlag(false) {
   // Initialize based upon command line options, if they are available.
   if (!clOptions.isConstructed())
     return;
@@ -239,6 +244,7 @@ OpPrintingFlags::OpPrintingFlags()
   printValueUsersFlag = clOptions->printValueUsers;
   printUniqueSSAIDsFlag = clOptions->printUniqueSSAIDs;
   useNameLocAsPrefix = clOptions->useNameLocAsPrefix;
+  printFloatSpecialLiteralsAsHexFlag = clOptions->printFloatSpecialLiteralsAsHexOpt;
 }
 
 /// Enable the elision of large elements attributes, by printing a '...'
@@ -331,6 +337,11 @@ OpPrintingFlags &OpPrintingFlags::printNameLocAsPrefix(bool enable) {
   return *this;
 }
 
+OpPrintingFlags &OpPrintingFlags::printFloatSpecialLiteralsAsHex(bool enable) {
+  printFloatSpecialLiteralsAsHexFlag = enable;
+  return *this;
+}
+
 /// Return the size limit for printing large ElementsAttr.
 std::optional<int64_t> OpPrintingFlags::getLargeElementsAttrLimit() const {
   return elementsAttrElementLimit;
@@ -387,6 +398,11 @@ bool OpPrintingFlags::shouldUseNameLocAsPrefix() const {
   return useNameLocAsPrefix;
 }
 
+/// Return if special float literals should print as a hexadecimal bit pattern.
+bool OpPrintingFlags::shouldPrintFloatSpecialLiteralsAsHex() const {
+  return printFloatSpecialLiteralsAsHexFlag;
+}
+
 //===----------------------------------------------------------------------===//
 // NewLineCounter
 //===----------------------------------------------------------------------===//
@@ -418,6 +434,9 @@ class AsmPrinter::Impl {
   /// Returns the output stream of the printer.
   raw_ostream &getStream() { return os; }
 
+  /// Returns the printing flags of the printer.
+  const OpPrintingFlags &getPrinterFlags() const { return printerFlags; }
+
   /// Print a newline and indent the printer to the start of the current
   /// operation/attribute/type.
   /// Note: For attributes and types this method should only be used in
@@ -2256,14 +2275,11 @@ void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty,
 /// Print a floating point value in a way that the parser will be able to
 /// round-trip losslessly.
 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
-                            bool *printedHex = nullptr) {
-  // We would like to output the FP constant value in exponential notation,
-  // but we cannot do this if doing so will lose precision.  Check here to
-  // make sure that we only output it in exponential format if we can parse
-  // the value back and get the same value.
-  bool isInf = apValue.isInfinity();
-  bool isNaN = apValue.isNaN();
-  if (!isInf && !isNaN) {
+                            bool *printedHex = nullptr,
+                            bool printFloatSpecialLiteralsAsHex = false) {
+  // Finite values print as decimal; this is the only form whose type may be
+  // elided.
+  if (!apValue.isInfinity() && !apValue.isNaN()) {
     SmallString<128> strValue;
     apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
                      /*TruncateZero=*/false);
@@ -2295,14 +2311,42 @@ static void printFloatValue(const APFloat &apValue, raw_ostream &os,
     }
   }
 
-  // Print special values in hexadecimal format. The sign bit should be included
-  // in the literal.
+  // The rest (inf, NaN, hex bit-pattern) are typeless; keep the type.
   if (printedHex)
     *printedHex = true;
+
+  // The legacy form prints inf/NaN as a hexadecimal bit pattern too.
+  if (!printFloatSpecialLiteralsAsHex && apValue.isInfinity()) {
+    os << (apValue.isNegative() ? "-inf" : "+inf");
+    return;
+  }
+
+  if (!printFloatSpecialLiteralsAsHex && apValue.isNaN()) {
+    os << (apValue.isNegative() ? '-' : '+');
+    APInt payload = apValue.getNaNPayload();
+    // Preferred quiet NaN = only the quiet (sign-mask) bit set. A zero-width
+    // payload (no mantissa bits, e.g. f8E8M0FNU) has none, so print qnan.
+    if (payload.getBitWidth() == 0 || payload.isSignMask()) {
+      os << "qnan";
+      return;
+    }
+    if (apValue.isSignaling())
+      os << 's';
+    os << "nan(";
+    // Drop the quiet/signaling bit; trim leading zeros.
+    payload.clearBit(payload.getBitWidth() - 1);
+    SmallVector<char, 16> str;
+    payload.trunc(std::max(payload.getActiveBits(), 1u))
+        .toString(str, /*Radix=*/16, /*Signed=*/false,
+                  /*formatAsCLiteral=*/true);
+    os << str << ')';
+    return;
+  }
+
+  // Hexadecimal bit pattern.
   SmallVector<char, 16> str;
-  APInt apInt = apValue.bitcastToAPInt();
-  apInt.toString(str, /*Radix=*/16, /*Signed=*/false,
-                 /*formatAsCLiteral=*/true);
+  apValue.bitcastToAPInt().toString(str, /*Radix=*/16, /*Signed=*/false,
+                                    /*formatAsCLiteral=*/true);
   os << str;
 }
 
@@ -2472,7 +2516,8 @@ void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
 
   } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
     bool printedHex = false;
-    printFloatValue(floatAttr.getValue(), os, &printedHex);
+    printFloatValue(floatAttr.getValue(), os, &printedHex,
+                    printerFlags.shouldPrintFloatSpecialLiteralsAsHex());
 
     // FloatAttr elides the type if F64.
     if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
@@ -2702,9 +2747,11 @@ void AsmPrinter::Impl::printDenseTypedElementsAttr(DenseTypedElementsAttr attr,
       printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
         auto complexValue = *(valueIt + index);
         os << "(";
-        printFloatValue(complexValue.real(), os);
+        printFloatValue(complexValue.real(), os, /*printedHex=*/nullptr,
+                        printerFlags.shouldPrintFloatSpecialLiteralsAsHex());
         os << ",";
-        printFloatValue(complexValue.imag(), os);
+        printFloatValue(complexValue.imag(), os, /*printedHex=*/nullptr,
+                        printerFlags.shouldPrintFloatSpecialLiteralsAsHex());
         os << ")";
       });
     }
@@ -2717,7 +2764,8 @@ void AsmPrinter::Impl::printDenseTypedElementsAttr(DenseTypedElementsAttr attr,
     assert(llvm::isa<FloatType>(elementType) && "unexpected element type");
     auto valueIt = attr.value_begin<APFloat>();
     printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
-      printFloatValue(*(valueIt + index), os);
+      printFloatValue(*(valueIt + index), os, /*printedHex=*/nullptr,
+                      printerFlags.shouldPrintFloatSpecialLiteralsAsHex());
     });
   }
 }
@@ -2768,7 +2816,8 @@ void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
       printDenseIntElement(value, getStream(), type);
     } else {
       APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
-      printFloatValue(fltVal, getStream());
+      printFloatValue(fltVal, getStream(), /*printedHex=*/nullptr,
+                      printerFlags.shouldPrintFloatSpecialLiteralsAsHex());
     }
   };
   llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
@@ -3063,7 +3112,8 @@ void AsmPrinter::decreaseIndent() {
 /// Print the given floating point value in a stablized form.
 void AsmPrinter::printFloat(const APFloat &value) {
   assert(impl && "expected AsmPrinter::printFloat to be overriden");
-  printFloatValue(value, impl->getStream());
+  printFloatValue(value, impl->getStream(), /*printedHex=*/nullptr,
+                  impl->getPrinterFlags().shouldPrintFloatSpecialLiteralsAsHex());
 }
 
 void AsmPrinter::printType(Type type) {
diff --git a/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation-ocp.mlir b/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation-ocp.mlir
index 2df5f2fa1965f..f66a7194d2afb 100644
--- a/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation-ocp.mlir
+++ b/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation-ocp.mlir
@@ -10,8 +10,8 @@
 // CHECK-SAME: ([[V:%.+]]: f16)
 // CHECK-DAG: [[CMin:%.+]] = arith.constant -5.734400e+04 : f16
 // CHECK-DAG: [[CMax:%.+]] = arith.constant 5.734400e+04 : f16
-// CHECK-DAG: [[CInf:%.+]] = arith.constant 0x7C00 : f16
-// CHECK-DAG: [[CNegInf:%.+]] = arith.constant 0xFC00 : f16
+// CHECK-DAG: [[CInf:%.+]] = arith.constant +inf : f16
+// CHECK-DAG: [[CNegInf:%.+]] = arith.constant -inf : f16
 // CHECK: [[ISINF:%.+]] = arith.cmpf oeq, [[V]], [[CInf]]
 // CHECK: [[ISNEGINF:%.+]] = arith.cmpf oeq, [[V]], [[CNegInf]]
 // CHECK: [[ISNAN:%.+]] = arith.cmpf uno, [[V]], [[V]]
@@ -37,8 +37,8 @@ func.func @scalar_trunc(%v: f16) -> f8E5M2 {
 // CHECK-SAME: ([[V:%.+]]: vector<2xf32>) -> vector<2xf8E4M3FN> {
 // CHECK-DAG: [[CMin:%.+]] = arith.constant dense<-4.480000e+02> : vector<2xf32>
 // CHECK-DAG: [[CMax:%.+]] = arith.constant dense<4.480000e+02> : vector<2xf32>
-// CHECK-DAG: [[CInf:%.+]] = arith.constant dense<0x7F800000> : vector<2xf32>
-// CHECK-DAG: [[CNegInf:%.+]] = arith.constant dense<0xFF800000> : vector<2xf32>
+// CHECK-DAG: [[CInf:%.+]] = arith.constant dense<+inf> : vector<2xf32>
+// CHECK-DAG: [[CNegInf:%.+]] = arith.constant dense<-inf> : vector<2xf32>
 // CHECK: [[ISINF:%.+]] = arith.cmpf oeq, [[V]], [[CInf]]
 // CHECK: [[ISNEGINF:%.+]] = arith.cmpf oeq, [[V]], [[CNegInf]]
 // CHECK: [[ISNAN:%.+]] = arith.cmpf uno, [[V]], [[V]]
diff --git a/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation.mlir b/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation.mlir
index 07a428566d488..f36b35b913c9b 100644
--- a/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation.mlir
+++ b/mlir/test/Conversion/ArithToAMDGPU/8-bit-float-saturation.mlir
@@ -6,8 +6,8 @@
 // CHECK-SAME: ([[V:%.+]]: f16)
 // CHECK-DAG: [[CMin:%.+]] = arith.constant -5.734400e+04 : f16
 // CHECK-DAG: [[CMax:%.+]] = arith.constant 5.734400e+04 : f16
-// CHECK-DAG: [[CInf:%.+]] = arith.constant 0x7C00 : f16
-// CHECK-DAG: [[CNegInf:%.+]] = arith.constant 0xFC00 : f16
+// CHECK-DAG: [[CInf:%.+]] = arith.constant +inf : f16
+// CHECK-DAG: [[CNegInf:%.+]] = arith.constant -inf : f16
 // CHECK: [[ISINF:%.+]] = arith.cmpf oeq, [[V]], [[CInf]]
 // CHECK: [[ISNEGINF:%.+]] = arith.cmpf oeq, [[V]], [[CNegInf]]
 // CHECK: [[ISNAN:%.+]] = arith.cmpf uno, [[V]], [[V]]
@@ -33,8 +33,8 @@ func.func @scalar_trunc(%v: f16) -> f8E5M2FNUZ {
 // CHECK-SAME: ([[V:%.+]]: vector<2xf32>) -> vector<2xf8E4M3FNUZ> {
 // CHECK-DAG: [[CMin:%.+]] = arith.constant dense<-2.400000e+02> : vector<2xf32>
 // CHECK-DAG: [[CMax:%.+]] = arith.constant dense<2.400000e+02> : vector<2xf32>
-// CHECK-DAG: [[CInf:%.+]] = arith.constant dense<0x7F800000> : vector<2xf32>
-// CHECK-DAG: [[CNegInf:%.+]] = arith.constant dense<0xFF800000> : vector<2xf32>
+// CHECK-DAG: [[CInf:%.+]] = arith.constant dense<+inf> : vector<2xf32>
+// CHECK-DAG: [[CNegInf:%.+]] = arith.constant dense<-inf> : vector<2xf32>
 // CHECK: [[ISINF:%.+]] = arith.cmpf oeq, [[V]], [[CInf]]
 // CHECK: [[ISNEGINF:%.+]] = arith.cmpf oeq, [[V]], [[CNegInf]]
 // CHECK: [[ISNAN:%.+]] = arith.cmpf uno, [[V]], [[V]]
diff --git a/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir b/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
index 78e8db795788a..cef9ec850387e 100644
--- a/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
+++ b/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
@@ -50,7 +50,7 @@ func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
 // DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = llvm.or %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // DIV-SMITH: %[[RHS_IS_ZERO:.*]] = llvm.and %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = llvm.and %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(0x7F800000 : f32) : f32
+// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(+inf : f32) : f32
 // DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = llvm.intr.copysign(%[[INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
 // DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] : f32
 // DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] : f32
@@ -200,7 +200,7 @@ func.func @complex_div_with_fmf(%lhs: complex<f32>, %rhs: complex<f32>) -> compl
 // DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = llvm.or %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // DIV-SMITH: %[[RHS_IS_ZERO:.*]] = llvm.and %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = llvm.and %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(0x7F800000 : f32) : f32
+// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(+inf : f32) : f32
 // DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = llvm.intr.copysign(%[[INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
 // DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
 // DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
diff --git a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
index deb4eb6d9d08c..9e1c540d8cd5b 100644
--- a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
+++ b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
@@ -46,7 +46,7 @@ func.func @complex_const() -> complex<f32> {
 }
 
 // CHECK-LABEL: func.func @complex_const()
-//       CHECK:   spirv.Constant dense<[0x7FC00000, 0.000000e+00]> : vector<2xf32>
+//       CHECK:   spirv.Constant dense<[+qnan, 0.000000e+00]> : vector<2xf32>
 
 // -----
 
diff --git a/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir b/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
index 97f37d8ebe77e..ce588fa5d20dc 100644
--- a/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
+++ b/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
@@ -46,7 +46,7 @@ func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
 // DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // DIV-SMITH: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// DIV-SMITH: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// DIV-SMITH: %[[INF:.*]] = arith.constant +inf : f32
 // DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
 // DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] : f32
 // DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] : f32
@@ -183,7 +183,7 @@ func.func @complex_div_with_fmf(%lhs: complex<f32>, %rhs: complex<f32>) -> compl
 // DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // DIV-SMITH: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// DIV-SMITH: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// DIV-SMITH: %[[INF:.*]] = arith.constant +inf : f32
 // DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
 // DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] fastmath<nsz,arcp> : f32
 // DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] fastmath<nsz,arcp> : f32
diff --git a/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir b/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir
index 1242b1b66ff7b..bef9163077b15 100644
--- a/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir
+++ b/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir
@@ -117,7 +117,7 @@ func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
 // CHECK: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // CHECK: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // CHECK: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
 // CHECK: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] : f32
 // CHECK: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] : f32
@@ -213,7 +213,7 @@ func.func @complex_exp(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[IMAG:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK-DAG: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
 // CHECK-DAG: %[[HALF:.*]] = arith.constant 5.000000e-01 : f32
-// CHECK-DAG: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK-DAG: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK-DAG: %[[EXP_REAL:.*]] = math.exp %[[REAL]] : f32
 // CHECK-DAG: %[[REAL_HALF:.*]] = arith.mulf %[[REAL]], %[[HALF]] : f32
 // CHECK-DAG: %[[EXP_HALF:.*]] = math.exp %[[REAL_HALF]] : f32
@@ -486,7 +486,7 @@ func.func @complex_tan(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[V0:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK: %[[NEG_ONE:.*]] = arith.constant -1.000000e+00 : f32
 // CHECK: %[[REAL:.*]] = arith.mulf %[[V0]], %[[NEG_ONE]] : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[FOUR:.*]] = arith.constant 4.000000e+00 : f32
 // CHECK: %[[TWO_REAL:.*]] = arith.addf %[[REAL]], %[[REAL]] : f32
 // CHECK: %[[NEG_TWO_REAL:.*]] = arith.mulf %[[NEG_ONE]], %[[TWO_REAL]] : f32
@@ -508,7 +508,7 @@ func.func @complex_tan(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_IMAG:.*]] = arith.divf %[[IMAG_NUM]], %[[DENOM]] : f32
 // CHECK: %[[ABS_REAL:.*]] = math.absf %[[REAL]] : f32
 // CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABS_REAL_INF:.*]] = arith.cmpf oeq, %[[ABS_REAL]], %[[INF]] : f32
 // CHECK: %[[IMAG_ZERO:.*]] = arith.cmpf oeq, %[[IMAG]], %[[ZERO]] : f32
 // CHECK: %true = arith.constant true
@@ -534,7 +534,7 @@ func.func @complex_tanh(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[REAL:.*]] = complex.re %[[ARG]] : complex<f32>
 // CHECK: %[[IMAG:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK: %[[NEG_ONE:.*]] = arith.constant -1.000000e+00 : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[FOUR:.*]] = arith.constant 4.000000e+00 : f32
 // CHECK: %[[TWO_REAL:.*]] = arith.addf %[[REAL]], %[[REAL]] : f32
 // CHECK: %[[NEG_TWO_REAL:.*]] = arith.mulf %[[NEG_ONE]], %[[TWO_REAL]] : f32
@@ -556,7 +556,7 @@ func.func @complex_tanh(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_IMAG:.*]] = arith.divf %[[IMAG_NUM]], %[[DENOM]] : f32
 // CHECK: %[[ABS_REAL:.*]] = math.absf %[[REAL]] : f32
 // CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABS_REAL_INF:.*]] = arith.cmpf oeq, %[[ABS_REAL]], %[[INF]] : f32
 // CHECK: %[[IMAG_ZERO:.*]] = arith.cmpf oeq, %[[IMAG]], %[[ZERO]] : f32
 // CHECK: %true = arith.constant true
@@ -605,9 +605,9 @@ func.func @complex_sqrt(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_RE:.*]] = arith.mulf %[[SQRT_ABS]], %[[COS]] : f32
 // CHECK: %[[RESULT_IM:.*]] = arith.mulf %[[SQRT_ABS]], %[[SIN]] : f32
 // CHECK: %[[RESULT_IM2:.*]] = arith.select %[[SIN_ZERO]], %[[ZERO]], %[[RESULT_IM]] : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
-// CHECK: %[[NINF:.*]] = arith.constant 0xFF800000 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
+// CHECK: %[[NINF:.*]] = arith.constant -inf : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABSIM:.*]] = math.absf %[[IM]] : f32
 // CHECK: %[[ABSIMINF:.*]] = arith.cmpf oeq, %[[ABSIM]], %[[INF]] : f32
 // CHECK: %[[ABSIMNOTINF:.*]] = arith.cmpf one, %[[ABSIM]], %[[INF]] : f32
@@ -847,7 +847,7 @@ func.func @complex_exp_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[IMAG:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK-DAG: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
 // CHECK-DAG: %[[HALF:.*]] = arith.constant 5.000000e-01 : f32
-// CHECK-DAG: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK-DAG: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK-DAG: %[[EXP_REAL:.*]] = math.exp %[[REAL]] fastmath<nnan,contract> : f32
 // CHECK-DAG: %[[REAL_HALF:.*]] = arith.mulf %[[REAL]], %[[HALF]] fastmath<nnan,contract> : f32
 // CHECK-DAG: %[[EXP_HALF:.*]] = math.exp %[[REAL_HALF]] fastmath<nnan,contract> : f32
@@ -1011,9 +1011,9 @@ func.func @complex_atan2_with_fmf(%lhs: complex<f32>,
 // CHECK: %[[RESULT_RE:.*]] = arith.mulf %[[SQRT_ABS]], %[[COS]] fastmath<nnan,contract> : f32
 // CHECK: %[[RESULT_IM:.*]] = arith.mulf %[[SQRT_ABS]], %[[SIN]] fastmath<nnan,contract> : f32
 // CHECK: %[[RESULT_IM2:.*]] = arith.select %[[SIN_ZERO]], %[[ZERO]], %[[RESULT_IM]] : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
-// CHECK: %[[NINF:.*]] = arith.constant 0xFF800000 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
+// CHECK: %[[NINF:.*]] = arith.constant -inf : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABSIM:.*]] = math.absf %[[IM]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABSIMINF:.*]] = arith.cmpf oeq, %[[ABSIM]], %[[INF]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABSIMNOTINF:.*]] = arith.cmpf one, %[[ABSIM]], %[[INF]] fastmath<nnan,contract> : f32
@@ -1084,7 +1084,7 @@ func.func @complex_atan2_with_fmf(%lhs: complex<f32>,
 // CHECK: %[[VAR355:.*]] = arith.ori %[[VAR353]], %[[VAR354]] : i1
 // CHECK: %[[VAR356:.*]] = arith.andi %[[VAR350]], %[[VAR352]] : i1
 // CHECK: %[[VAR357:.*]] = arith.andi %[[VAR355]], %[[VAR356]] : i1
-// CHECK: %[[CST_17:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[CST_17:.*]] = arith.constant +inf : f32
 // CHECK: %[[VAR358:.*]] = math.copysign %[[CST_17]], %[[VAR329]] : f32
 // CHECK: %[[VAR359:.*]] = arith.mulf %[[VAR358]], %[[VAR327]] fastmath<nnan,contract> : f32
 // CHECK: %[[VAR360:.*]] = arith.mulf %[[VAR358]], %[[VAR328]] fastmath<nnan,contract> : f32
@@ -1221,7 +1221,7 @@ func.func @complex_div_with_fmf(%lhs: complex<f32>, %rhs: complex<f32>) -> compl
 // CHECK: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
 // CHECK: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
 // CHECK: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
 // CHECK: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] fastmath<nnan,contract> : f32
 // CHECK: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] fastmath<nnan,contract> : f32
@@ -1323,9 +1323,9 @@ func.func @complex_sqrt_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_RE:.*]] = arith.mulf %[[SQRT_ABS]], %[[COS]] fastmath<nnan,contract> : f32
 // CHECK: %[[RESULT_IM:.*]] = arith.mulf %[[SQRT_ABS]], %[[SIN]] fastmath<nnan,contract> : f32
 // CHECK: %[[RESULT_IM2:.*]] = arith.select %[[SIN_ZERO]], %[[ZERO]], %[[RESULT_IM]] : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
-// CHECK: %[[NINF:.*]] = arith.constant 0xFF800000 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
+// CHECK: %[[NINF:.*]] = arith.constant -inf : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABSIM:.*]] = math.absf %[[IM]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABSIMINF:.*]] = arith.cmpf oeq, %[[ABSIM]], %[[INF]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABSIMNOTINF:.*]] = arith.cmpf one, %[[ABSIM]], %[[INF]] fastmath<nnan,contract> : f32
@@ -1440,7 +1440,7 @@ func.func @complex_tan_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[V0:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK: %[[NEG_ONE:.*]] = arith.constant -1.000000e+00 : f32
 // CHECK: %[[REAL:.*]] = arith.mulf %[[V0]], %cst fastmath<nnan,contract> : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[FOUR:.*]] = arith.constant 4.000000e+00 : f32
 // CHECK: %[[TWO_REAL:.*]] = arith.addf %[[REAL]], %[[REAL]] fastmath<nnan,contract> : f32
 // CHECK: %[[NEG_TWO_REAL:.*]] = arith.mulf %[[NEG_ONE]], %[[TWO_REAL]] fastmath<nnan,contract> : f32
@@ -1462,7 +1462,7 @@ func.func @complex_tan_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_IMAG:.*]] = arith.divf %[[IMAG_NUM]], %[[DENOM]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABS_REAL:.*]] = math.absf %[[REAL]] fastmath<nnan,contract> : f32
 // CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABS_REAL_INF:.*]] = arith.cmpf oeq, %[[ABS_REAL]], %[[INF]] fastmath<nnan,contract> : f32
 // CHECK: %[[IMAG_ZERO:.*]] = arith.cmpf oeq, %[[IMAG]], %[[ZERO]] fastmath<nnan,contract> : f32
 // CHECK: %true = arith.constant true
@@ -1489,7 +1489,7 @@ func.func @complex_tanh_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[REAL:.*]] = complex.re %[[ARG]] : complex<f32>
 // CHECK: %[[IMAG:.*]] = complex.im %[[ARG]] : complex<f32>
 // CHECK: %[[NEG_ONE:.*]] = arith.constant -1.000000e+00 : f32
-// CHECK: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// CHECK: %[[INF:.*]] = arith.constant +inf : f32
 // CHECK: %[[FOUR:.*]] = arith.constant 4.000000e+00 : f32
 // CHECK: %[[TWO_REAL:.*]] = arith.addf %[[REAL]], %[[REAL]] fastmath<nnan,contract> : f32
 // CHECK: %[[NEG_TWO_REAL:.*]] = arith.mulf %[[NEG_ONE]], %[[TWO_REAL]] fastmath<nnan,contract> : f32
@@ -1511,7 +1511,7 @@ func.func @complex_tanh_with_fmf(%arg: complex<f32>) -> complex<f32> {
 // CHECK: %[[RESULT_IMAG:.*]] = arith.divf %[[IMAG_NUM]], %[[DENOM]] fastmath<nnan,contract> : f32
 // CHECK: %[[ABS_REAL:.*]] = math.absf %[[REAL]] fastmath<nnan,contract> : f32
 // CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
-// CHECK: %[[NAN:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK: %[[NAN:.*]] = arith.constant +qnan : f32
 // CHECK: %[[ABS_REAL_INF:.*]] = arith.cmpf oeq, %[[ABS_REAL]], %[[INF]] fastmath<nnan,contract> : f32
 // CHECK: %[[IMAG_ZERO:.*]] = arith.cmpf oeq, %[[IMAG]], %[[ZERO]] fastmath<nnan,contract> : f32
 // CHECK: %true = arith.constant true
diff --git a/mlir/test/Conversion/GPUToNVVM/wmma-ops-to-nvvm.mlir b/mlir/test/Conversion/GPUToNVVM/wmma-ops-to-nvvm.mlir
index a0801443057ea..eaacce2f91e7f 100644
--- a/mlir/test/Conversion/GPUToNVVM/wmma-ops-to-nvvm.mlir
+++ b/mlir/test/Conversion/GPUToNVVM/wmma-ops-to-nvvm.mlir
@@ -335,7 +335,7 @@ gpu.module @test_module {
 //       CHECK: %[[CMP0:.*]] = llvm.fcmp "ogt" %[[A0]], %[[B0]] : vector<2xf16>
 //       CHECK: %[[SEL0:.*]] = llvm.select %[[CMP0]], %[[A0]], %[[B0]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[CMP1:.*]] = llvm.fcmp "uno" %[[A0]], %[[B0]] : vector<2xf16>
-//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(0x7E00 : f16) : vector<2xf16>
+//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(+qnan : f16) : vector<2xf16>
 //       CHECK: %[[C0:.*]] = llvm.select %[[CMP1]], %[[NAN]], %[[SEL0]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[M1:.*]] = llvm.insertvalue %[[C0]], %[[M0]][0] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
 //       CHECK: %[[A1:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
@@ -343,7 +343,7 @@ gpu.module @test_module {
 //       CHECK: %[[CMP2:.*]] = llvm.fcmp "ogt" %[[A1]], %[[B1]] : vector<2xf16>
 //       CHECK: %[[SEL1:.*]] = llvm.select %[[CMP2]], %[[A1]], %[[B1]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[CMP3:.*]] = llvm.fcmp "uno" %[[A1]], %[[B1]] : vector<2xf16>
-//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(0x7E00 : f16) : vector<2xf16>
+//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(+qnan : f16) : vector<2xf16>
 //       CHECK: %[[C1:.*]] = llvm.select %[[CMP3]], %[[NAN]], %[[SEL1]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[M2:.*]] = llvm.insertvalue %[[C1]], %[[M1]][1] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
 //       CHECK: %[[A2:.*]] = llvm.extractvalue %{{.*}}[2] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
@@ -351,7 +351,7 @@ gpu.module @test_module {
 //       CHECK: %[[CMP4:.*]] = llvm.fcmp "ogt" %[[A2]], %[[B2]] : vector<2xf16>
 //       CHECK: %[[SEL2:.*]] = llvm.select %[[CMP4]], %[[A2]], %[[B2]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[CMP5:.*]] = llvm.fcmp "uno" %[[A2]], %[[B2]] : vector<2xf16>
-//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(0x7E00 : f16) : vector<2xf16>
+//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(+qnan : f16) : vector<2xf16>
 //       CHECK: %[[C2:.*]] = llvm.select %[[CMP5]], %[[NAN]], %[[SEL2]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[M3:.*]] = llvm.insertvalue %[[C2]], %[[M2]][2] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
 //       CHECK: %[[A3:.*]] = llvm.extractvalue %{{.*}}[3] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
@@ -359,7 +359,7 @@ gpu.module @test_module {
 //       CHECK: %[[CMP6:.*]] = llvm.fcmp "ogt" %[[A3]], %[[B3]] : vector<2xf16>
 //       CHECK: %[[SEL3:.*]] = llvm.select %[[CMP6]], %[[A3]], %[[B3]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[CMP7:.*]] = llvm.fcmp "uno" %[[A3]], %[[B3]] : vector<2xf16>
-//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(0x7E00 : f16) : vector<2xf16>
+//       CHECK: %[[NAN:.*]] = llvm.mlir.constant(+qnan : f16) : vector<2xf16>
 //       CHECK: %[[C3:.*]] = llvm.select %[[CMP7]], %[[NAN]], %[[SEL3]] : vector<2xi1>, vector<2xf16>
 //       CHECK: %[[M5:.*]] = llvm.insertvalue %[[C3]], %[[M3]][3] : !llvm.struct<(vector<2xf16>, vector<2xf16>, vector<2xf16>, vector<2xf16>)>
 
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
index e6bd800a0cf0a..938426c271f82 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
@@ -601,8 +601,8 @@ func.func @test_simple_f16(%arg0: tensor<1xf16>) -> () {
   // CHECK: linalg.generic
   // CHECK: [[ROUND:%.+]] = math.roundeven {{%[a-z0-9_]+}} : f16
   // CHECK: [[CONV:%.+]] = arith.fptosi [[ROUND]] : f16 to i32
-  // CHECK: [[POSINF:%.+]] = arith.constant 0x7C00 : f16
-  // CHECK: [[NEGINF:%.+]] = arith.constant 0xFC00 : f16
+  // CHECK: [[POSINF:%.+]] = arith.constant +inf : f16
+  // CHECK: [[NEGINF:%.+]] = arith.constant -inf : f16
   // CHECK: [[OVERFLOW:%.+]] = arith.cmpf ueq, [[ROUND]], [[POSINF]] : f16
   // CHECK: [[UNDERFLOW:%.+]] = arith.cmpf ueq, [[ROUND]], [[NEGINF]] : f16
   // CHECK: [[MININT:%.+]] = arith.constant -2147483648 : i32
@@ -2334,7 +2334,7 @@ func.func @reduce_min_nan_propagate(%arg0: tensor<5x4xf32>, %arg1: tensor<5x4xf3
   // CHECK-NOT: arith.cmpf uno
   // CHECK-NOT: arith.select
   // CHECK: linalg.yield
-  // CHECK-NOT: arith.constant 0x7FC00000
+  // CHECK-NOT: arith.constant +qnan
   // CHECK-NOT: tensor.empty()
   // CHECK-NOT: linalg.fill
   // CHECK-NOT: tensor.empty()
@@ -2353,7 +2353,7 @@ func.func @reduce_max_nan_propagate(%arg0: tensor<5x4xf32>, %arg1: tensor<5x4xf3
   // CHECK-NOT: arith.cmpf uno
   // CHECK-NOT: arith.select
   // CHECK: linalg.yield
-  // CHECK-NOT: arith.constant 0x7FC00000
+  // CHECK-NOT: arith.constant +qnan
   // CHECK-NOT: tensor.empty()
   // CHECK-NOT: linalg.fill
   // CHECK-NOT: tensor.empty()
@@ -2372,7 +2372,7 @@ func.func @reduce_min_nan_ignore_int(%arg0: tensor<5x4xi8>, %arg1: tensor<5x4xi8
   // CHECK-NOT: arith.cmpf uno
   // CHECK-NOT: arith.select
   // CHECK: linalg.yield
-  // CHECK-NOT: arith.constant 0x7FC00000
+  // CHECK-NOT: arith.constant +qnan
   // CHECK-NOT: tensor.empty()
   // CHECK-NOT: linalg.fill
   // CHECK-NOT: tensor.empty()
@@ -2391,7 +2391,7 @@ func.func @reduce_max_nan_ignore_int(%arg0: tensor<5x4xi8>, %arg1: tensor<5x4xi8
   // CHECK-NOT: arith.cmpf uno
   // CHECK-NOT: arith.select
   // CHECK: linalg.yield
-  // CHECK-NOT: arith.constant 0x7FC00000
+  // CHECK-NOT: arith.constant +qnan
   // CHECK-NOT: tensor.empty()
   // CHECK-NOT: linalg.fill
   // CHECK-NOT: tensor.empty()
@@ -2410,7 +2410,7 @@ func.func @reduce_min_nan_ignore(%arg0: tensor<5x4xf32>, %arg1: tensor<5x4xf32>)
   // CHECK: arith.cmpf uno
   // CHECK: arith.select
   // CHECK: linalg.yield
-  // CHECK: arith.constant 0x7FC00000
+  // CHECK: arith.constant +qnan
   // CHECK: tensor.empty()
   // CHECK: linalg.fill
   // CHECK: tensor.empty()
@@ -2428,7 +2428,7 @@ func.func @reduce_max_nan_ignore(%arg0: tensor<5x4xf32>, %arg1: tensor<5x4xf32>)
   // CHECK: arith.cmpf uno
   // CHECK: arith.select
   // CHECK: linalg.yield
-  // CHECK: arith.constant 0x7FC00000
+  // CHECK: arith.constant +qnan
   // CHECK: tensor.empty()
   // CHECK: linalg.fill
   // CHECK: tensor.empty()
diff --git a/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir b/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
index c7d9e22fb2423..4a536c003abb3 100644
--- a/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
+++ b/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
@@ -123,7 +123,7 @@ func.func @masked_reduce_minf_f32(%arg0: vector<16xf32>, %mask : vector<16xi1>)
 // CHECK-LABEL:   func.func @masked_reduce_minf_f32(
 // CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
 // CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
-// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(0xFFC00000 : f32) : f32
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(-qnan : f32) : f32
 // CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
 // CHECK:           "llvm.intr.vp.reduce.fmin"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
 
@@ -137,7 +137,7 @@ func.func @masked_reduce_minf_f32_scalable(%arg0: vector<[16]xf32>, %mask : vect
 // CHECK-LABEL:   func.func @masked_reduce_minf_f32_scalable(
 // CHECK-SAME:                                      %[[INPUT:.*]]: vector<[16]xf32>,
 // CHECK-SAME:                                      %[[MASK:.*]]: vector<[16]xi1>) -> f32 {
-// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(0xFFC00000 : f32) : f32
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(-qnan : f32) : f32
 // CHECK:           %[[VL_BASE:.*]] = llvm.mlir.constant(16 : i32) : i32
 // CHECK:           %[[VSCALE:.*]] = "llvm.intr.vscale"() : () -> i64
 // CHECK:           %[[CAST_IDX:.*]] = builtin.unrealized_conversion_cast %[[VSCALE]] : i64 to index
@@ -155,7 +155,7 @@ func.func @masked_reduce_maxf_f32(%arg0: vector<16xf32>, %mask : vector<16xi1>)
 // CHECK-LABEL:   func.func @masked_reduce_maxf_f32(
 // CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
 // CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
-// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(0x7FC00000 : f32) : f32
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(+qnan : f32) : f32
 // CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
 // CHECK:           "llvm.intr.vp.reduce.fmax"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
 
diff --git a/mlir/test/Dialect/Affine/SuperVectorize/vectorize_reduction.mlir b/mlir/test/Dialect/Affine/SuperVectorize/vectorize_reduction.mlir
index 9dacc316f1072..31dffa96adace 100644
--- a/mlir/test/Dialect/Affine/SuperVectorize/vectorize_reduction.mlir
+++ b/mlir/test/Dialect/Affine/SuperVectorize/vectorize_reduction.mlir
@@ -44,7 +44,7 @@ func.func @vecdim_reduction_minf(%in: memref<256x512xf32>, %out: memref<256xf32>
 
 // CHECK-LABEL: @vecdim_reduction_minf
 // CHECK:       affine.for %{{.*}} = 0 to 256 {
-// CHECK:         %[[vmax:.*]] = arith.constant dense<0x7F800000> : vector<128xf32>
+// CHECK:         %[[vmax:.*]] = arith.constant dense<+inf> : vector<128xf32>
 // CHECK:         %[[vred:.*]] = affine.for %{{.*}} = 0 to 512 step 128 iter_args(%[[red_iter:.*]] = %[[vmax]]) -> (vector<128xf32>) {
 // CHECK:           %[[ld:.*]] = vector.transfer_read %{{.*}} : memref<256x512xf32>, vector<128xf32>
 // CHECK:           %[[min:.*]] = arith.minimumf %[[red_iter]], %[[ld]] : vector<128xf32>
@@ -71,7 +71,7 @@ func.func @vecdim_reduction_maxf(%in: memref<256x512xf32>, %out: memref<256xf32>
 
 // CHECK-LABEL: @vecdim_reduction_maxf
 // CHECK:       affine.for %{{.*}} = 0 to 256 {
-// CHECK:         %[[vmin:.*]] = arith.constant dense<0xFF800000> : vector<128xf32>
+// CHECK:         %[[vmin:.*]] = arith.constant dense<-inf> : vector<128xf32>
 // CHECK:         %[[vred:.*]] = affine.for %{{.*}} = 0 to 512 step 128 iter_args(%[[red_iter:.*]] = %[[vmin]]) -> (vector<128xf32>) {
 // CHECK:           %[[ld:.*]] = vector.transfer_read %{{.*}} : memref<256x512xf32>, vector<128xf32>
 // CHECK:           %[[max:.*]] = arith.maximumf %[[red_iter]], %[[ld]] : vector<128xf32>
@@ -294,9 +294,9 @@ func.func @vecdim_reduction_minnumf(%in: memref<256x512xf32>, %out: memref<256xf
 // CHECK-LABEL:   func.func @vecdim_reduction_minnumf(
 // CHECK-SAME:      %[[input:.*]]: memref<256x512xf32>,
 // CHECK-SAME:      %[[output:.*]]: memref<256xf32>) {
-// CHECK:           %[[cst:.*]] = arith.constant 0xFF800000 : f32
+// CHECK:           %[[cst:.*]] = arith.constant -inf : f32
 // CHECK:           affine.for %{{.*}} = 0 to 256 {
-// CHECK:             %[[vzero:.*]] = arith.constant dense<0x7FC00000> : vector<128xf32>
+// CHECK:             %[[vzero:.*]] = arith.constant dense<+qnan> : vector<128xf32>
 // CHECK:             %[[vred:.*]] = affine.for %{{.*}} = 0 to 512 step 128 iter_args(%[[red_iter:.*]] = %[[vzero]]) -> (vector<128xf32>) {
 // CHECK:               %[[poison:.*]] = ub.poison : f32
 // CHECK:               %[[ld:.*]] = vector.transfer_read %[[input]]{{\[}}%{{.*}}, %{{.*}}], %[[poison]] {in_bounds = [true]} : memref<256x512xf32>, vector<128xf32>
@@ -328,9 +328,9 @@ func.func @vecdim_reduction_maxnumf(%in: memref<256x512xf32>, %out: memref<256xf
 // CHECK-LABEL:   func.func @vecdim_reduction_maxnumf(
 // CHECK-SAME:      %[[input:.*]]: memref<256x512xf32>,
 // CHECK-SAME:      %[[output:.*]]: memref<256xf32>) {
-// CHECK:           %[[cst:.*]] = arith.constant 0xFF800000 : f32
+// CHECK:           %[[cst:.*]] = arith.constant -inf : f32
 // CHECK:           affine.for %{{.*}} = 0 to 256 {
-// CHECK:             %[[vzero:.*]] = arith.constant dense<0xFFC00000> : vector<128xf32>
+// CHECK:             %[[vzero:.*]] = arith.constant dense<-qnan> : vector<128xf32>
 // CHECK:             %[[vred:.*]] = affine.for %{{.*}} = 0 to 512 step 128 iter_args(%[[red_iter:.*]] = %[[vzero]]) -> (vector<128xf32>) {
 // CHECK:               %[[poison:.*]] = ub.poison : f32
 // CHECK:               %[[ld:.*]] = vector.transfer_read %[[input]]{{\[}}%{{.*}}, %{{.*}}], %[[poison]] {in_bounds = [true]} : memref<256x512xf32>, vector<128xf32>
diff --git a/mlir/test/Dialect/Arith/emulate-wide-int.mlir b/mlir/test/Dialect/Arith/emulate-wide-int.mlir
index 695d8fd453fd7..b23121cf101cc 100644
--- a/mlir/test/Dialect/Arith/emulate-wide-int.mlir
+++ b/mlir/test/Dialect/Arith/emulate-wide-int.mlir
@@ -991,7 +991,7 @@ func.func @uitofp_i64_f64_vector(%a : vector<3xi64>) -> vector<3xf64> {
 // CHECK-NEXT:    [[HIEQ0:%.+]]  = arith.cmpi eq, [[HI]], [[CST0]] : i32
 // CHECK-NEXT:    [[LOWFP:%.+]]  = arith.uitofp [[LOW]] : i32 to f16
 // CHECK-NEXT:    [[HIFP:%.+]]   = arith.uitofp [[HI]] : i32 to f16
-// CHECK-NEXT:    [[POW:%.+]]    = arith.constant 0x7C00 : f16
+// CHECK-NEXT:    [[POW:%.+]]    = arith.constant +inf : f16
 // CHECK-NEXT:    [[RESHI:%.+]]  = arith.mulf [[HIFP]], [[POW]] : f16
 // CHECK-NEXT:    [[RES:%.+]]    = arith.addf [[LOWFP]], [[RESHI]] : f16
 // CHECK-NEXT:    [[SEL:%.+]]    = arith.select [[HIEQ0]], [[LOWFP]], [[RES]] : f16
diff --git a/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir b/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
index 7dedfbdff10a7..978c29de3fc85 100644
--- a/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
+++ b/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
@@ -97,12 +97,12 @@ module @TestDenseStringElementsAttr attributes {
 // CHECK-LABEL: @TestFloat
 module @TestFloat attributes {
   // CHECK: bytecode.float = 1.000000e+01 : f64
-  // CHECK: bytecode.float1 = 0.10000{{.*}} : f80
-  // CHECK: bytecode.float2 = 0.10000{{.*}} : f128
+  // CHECK: bytecode.float1 = 1.000000e-01 : f80
+  // CHECK: bytecode.float2 = 1.000000e-01 : f128
   // CHECK: bytecode.float3 = -5.000000e-01 : bf16
-  // CHECK: bytecode.inf = 0x7FF0000000000000 : f64
-  // CHECK: bytecode.nan = 0x7FF8000000000000 : f64
-  // CHECK: bytecode.ninf = 0xFFF0000000000000 : f64
+  // CHECK: bytecode.inf = +inf : f64
+  // CHECK: bytecode.nan = +qnan : f64
+  // CHECK: bytecode.ninf = -inf : f64
   bytecode.float = 10.0 : f64,
   bytecode.float1 = 0.1 : f80,
   bytecode.float2 = 0.1 : f128,
diff --git a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
index d427035435277..ebb198456b3c1 100644
--- a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
+++ b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
@@ -125,8 +125,8 @@ module @TestFloatAttr attributes {
   // CHECK-DAG: bytecode.f16 = 1.500000e+00 : f16
   // CHECK-DAG: bytecode.f32 = 3.140000e+00 : f32
   // CHECK-DAG: bytecode.f64 = 1.000000e+01 : f64
-  // CHECK-DAG: bytecode.f80 = 0.1{{.*}} : f80
-  // CHECK-DAG: bytecode.f128 = 0.1{{.*}} : f128
+  // CHECK-DAG: bytecode.f80 = 1.000000e-01 : f80
+  // CHECK-DAG: bytecode.f128 = 1.000000e-01 : f128
   // CHECK-DAG: bytecode.tf32 = 1.000000e+00 : tf32
   // CHECK-DAG: bytecode.f8E5M2 = 1.000000e+00 : f8E5M2
   // CHECK-DAG: bytecode.f8E4M3 = 1.000000e+00 : f8E4M3
diff --git a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc
index 95be4de8fd1ab202b51658ce69f8037276dd74e8..4f661b5a1d233336116b303958bc724529f88b5a 100644
GIT binary patch
delta 27
ecmcbobx&)<4<?S&XCPn_vo2F=+Gc%beIWqP@(kAi

delta 27
ecmcbobx&)<4<?TP5U_s|vo6#B_|5vv`a%Hd#SX&&

diff --git a/mlir/test/Dialect/Complex/canonicalize.mlir b/mlir/test/Dialect/Complex/canonicalize.mlir
index 1c5216c82e5c3..065e1a9cdb4c9 100644
--- a/mlir/test/Dialect/Complex/canonicalize.mlir
+++ b/mlir/test/Dialect/Complex/canonicalize.mlir
@@ -332,7 +332,7 @@ func.func @div_op_with_rhs_has_nan_real() -> complex<f32> {
   %a = complex.constant [0x7fffffff : f32, 1.0 : f32]: complex<f32>
   %b = complex.constant [1.0: f32, 0.0 : f32]: complex<f32>
   %div = complex.div %a, %b : complex<f32>
-  // CHECK: %[[DIV:.*]] = complex.constant [0x7FFFFFFF : f32, 0x7FFFFFFF : f32] : complex<f32>
+  // CHECK: %[[DIV:.*]] = complex.constant [+nan(0x3FFFFF) : f32, +nan(0x3FFFFF) : f32] : complex<f32>
   // CHECK: return %[[DIV]] : complex<f32>
   return %div : complex<f32>
 }
@@ -342,7 +342,7 @@ func.func @div_op_with_rhs_has_nan_imag() -> complex<f32> {
   %a = complex.constant [1.0 : f32, 0x7fffffff : f32]: complex<f32>
   %b = complex.constant [1.0: f32, 0.0 : f32]: complex<f32>
   %div = complex.div %a, %b : complex<f32>
-  // CHECK: %[[DIV:.*]] = complex.constant [0x7FFFFFFF : f32, 0x7FFFFFFF : f32] : complex<f32>
+  // CHECK: %[[DIV:.*]] = complex.constant [+nan(0x3FFFFF) : f32, +nan(0x3FFFFF) : f32] : complex<f32>
   // CHECK: return %[[DIV]] : complex<f32>
   return %div : complex<f32>
 }
@@ -352,7 +352,7 @@ func.func @div_op_with_rhs_has_nan_real_imag() -> complex<f32> {
   %a = complex.constant [0x7fffffff : f32, 0x7fffffff : f32]: complex<f32>
   %b = complex.constant [1.0: f32, 0.0 : f32]: complex<f32>
   %div = complex.div %a, %b : complex<f32>
-  // CHECK: %[[DIV:.*]] = complex.constant [0x7FFFFFFF : f32, 0x7FFFFFFF : f32] : complex<f32>
+  // CHECK: %[[DIV:.*]] = complex.constant [+nan(0x3FFFFF) : f32, +nan(0x3FFFFF) : f32] : complex<f32>
   // CHECK: return %[[DIV]] : complex<f32>
   return %div : complex<f32>
 }
diff --git a/mlir/test/Dialect/Linalg/transform-op-decompose.mlir b/mlir/test/Dialect/Linalg/transform-op-decompose.mlir
index 3897f8502bb04..deb59e8fc3ab0 100644
--- a/mlir/test/Dialect/Linalg/transform-op-decompose.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-decompose.mlir
@@ -369,7 +369,7 @@ func.func @softmax(%arg0: tensor<2x16x32xf32>, %dst: tensor<2x16x32xf32>) -> ten
 // CHECK-LABEL:      func.func @softmax(
 // CHECK-SAME:           %[[ARG0:[a-zA-Z0-9_]+]]: tensor<2x16x32xf32>, %[[DST:[a-zA-Z0-9_]+]]: tensor<2x16x32xf32>) -> tensor<2x16x32xf32> {
 // CHECK-DAG:        %[[D1:.+]] = tensor.empty() : tensor<2x16xf32>
-// CHECK-DAG:        %[[CST:.+]] = arith.constant 0xFFC00000 : f32
+// CHECK-DAG:        %[[CST:.+]] = arith.constant -qnan : f32
 // CHECK:        %[[D2:.+]] = linalg.fill ins(%[[CST]] : f32) outs(%[[D1]] : tensor<2x16xf32>) -> tensor<2x16xf32>
 // CHECK:        %[[D3:.+]] = linalg.generic {indexing_maps = [#[[$MAP]], #[[$MAP1]]], iterator_types = ["parallel",
 // CHECK-SAME:     "parallel", "reduction"]} ins(%[[ARG0]] : tensor<2x16x32xf32>) outs(%[[D2]] : tensor<2x16xf32>) {
diff --git a/mlir/test/Dialect/Linalg/transform-op-split-reduction.mlir b/mlir/test/Dialect/Linalg/transform-op-split-reduction.mlir
index 9849f36285b16..a97f0a3327acb 100644
--- a/mlir/test/Dialect/Linalg/transform-op-split-reduction.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-split-reduction.mlir
@@ -118,7 +118,7 @@ func.func @generic_split_3d(%input: tensor<32x2xf32>, %input_2: tensor<5x32xf32>
 //  CHECK-DAG: #[[$MAP3:.*]] = affine_map<(d0, d1, d2) -> (d0, d1, d2)>
 //  CHECK-DAG: #[[$MAP4:.*]] = affine_map<(d0, d1, d2) -> (d0, d1)>
 // CHECK-LABEL:  func @generic_split_3d
-//  CHECK-DAG: %[[ID:.*]] = arith.constant 0xFF800000 : f32
+//  CHECK-DAG: %[[ID:.*]] = arith.constant -inf : f32
 //  CHECK-DAG: %[[I1:.*]] = tensor.expand_shape %{{.*}}[0, 1], [2]] output_shape [4, 8, 2] : tensor<32x2xf32> into tensor<4x8x2xf32>
 //  CHECK-DAG: %[[I2:.*]] = tensor.expand_shape %{{.*}}[0], [1, 2]] output_shape [5, 4, 8] : tensor<5x32xf32> into tensor<5x4x8xf32>
 //  CHECK-DAG: %[[INI:.*]] = tensor.empty() : tensor<5x2x4xf32>
@@ -323,7 +323,7 @@ func.func @generic_split_3d(%input: tensor<32x2xf32>, %input_2: tensor<5x32xf32>
 //  CHECK-DAG: #[[$MAP3:.*]] = affine_map<(d0, d1, d2) -> (d0, d1, d2)>
 //  CHECK-DAG: #[[$MAP4:.*]] = affine_map<(d0, d1, d2) -> (d0, d1)>
 // CHECK-LABEL:  func @generic_split_3d
-//  CHECK-DAG: %[[ID:.*]] = arith.constant 0x7F800000 : f32
+//  CHECK-DAG: %[[ID:.*]] = arith.constant +inf : f32
 //  CHECK-DAG: %[[I1:.*]] = tensor.expand_shape %{{.*}}[0, 1], [2]] output_shape [8, 4, 2] : tensor<32x2xf32> into tensor<8x4x2xf32>
 //  CHECK-DAG: %[[I2:.*]] = tensor.expand_shape %{{.*}}[0], [1, 2]] output_shape [5, 8, 4] : tensor<5x32xf32> into tensor<5x8x4xf32>
 //  CHECK-DAG: %[[INI:.*]] = tensor.empty() : tensor<5x2x4xf32>
@@ -429,7 +429,7 @@ func.func @generic_split_maxnumf(%in: tensor<32xf32>, %out: tensor<f32>) -> tens
 //  CHECK-DAG: #[[$MAP3:.*]] = affine_map<(d0) -> ()>
 // CHECK-LABEL:  func @generic_split_maxnumf
 //  The float value 0xFFC00000 that is filled into the init tensor represents negative NaN.
-//  CHECK-DAG: %[[ID:.*]] = arith.constant 0xFFC00000 : f32
+//  CHECK-DAG: %[[ID:.*]] = arith.constant -qnan : f32
 //  CHECK-DAG: %[[I1:.*]] = tensor.expand_shape %{{.*}}[0, 1]] output_shape [8, 4] : tensor<32xf32> into tensor<8x4xf32>
 //  CHECK-DAG: %[[INI:.*]] = tensor.empty() : tensor<4xf32>
 //      CHECK: %[[F:.*]] = linalg.fill ins(%[[ID]] : f32) outs(%[[INI]] : tensor<4xf32>) -> tensor<4xf32>
@@ -475,7 +475,7 @@ func.func @generic_split_minnumf(%in: tensor<32xf32>, %out: tensor<f32>) -> tens
 //  CHECK-DAG: #[[$MAP3:.*]] = affine_map<(d0) -> ()>
 // CHECK-LABEL:  func @generic_split_minnumf
 //  The float value 0x7FC00000 that is filled into the init tensor represents positive NaN.
-//  CHECK-DAG: %[[ID:.*]] = arith.constant 0x7FC00000 : f32
+//  CHECK-DAG: %[[ID:.*]] = arith.constant +qnan : f32
 //  CHECK-DAG: %[[I1:.*]] = tensor.expand_shape %{{.*}}[0, 1]] output_shape [8, 4] : tensor<32xf32> into tensor<8x4xf32>
 //  CHECK-DAG: %[[INI:.*]] = tensor.empty() : tensor<4xf32>
 //      CHECK: %[[F:.*]] = linalg.fill ins(%[[ID]] : f32) outs(%[[INI]] : tensor<4xf32>) -> tensor<4xf32>
diff --git a/mlir/test/Dialect/Linalg/transform-tile-reduction.mlir b/mlir/test/Dialect/Linalg/transform-tile-reduction.mlir
index 25af6796d1f63..daa80a98c9af0 100644
--- a/mlir/test/Dialect/Linalg/transform-tile-reduction.mlir
+++ b/mlir/test/Dialect/Linalg/transform-tile-reduction.mlir
@@ -317,7 +317,7 @@ module attributes {transform.with_named_sequence} {
 
 // CHECK: func @reduction_tile_multiple_results
 // CHECK-DAG:   %[[SUM_ID:.+]] = arith.constant 0.000000e+00 : f32
-// CHECK-DAG:   %[[MAX_ID:.+]] = arith.constant 0xFF800000 : f32
+// CHECK-DAG:   %[[MAX_ID:.+]] = arith.constant -inf : f32
 // CHECK-DAG:   %[[SUM_INIT:.+]] = linalg.fill ins(%[[SUM_ID]] : f32) outs(%{{.*}} : tensor<?x5xf32>) -> tensor<?x5xf32>
 // CHECK-DAG:   %[[MAX_INIT:.+]] = linalg.fill ins(%[[MAX_ID]] : f32) outs(%{{.*}} : tensor<?x5xf32>) -> tensor<?x5xf32>
 // CHECK:       %[[OUT:.+]]:2 = scf.for
diff --git a/mlir/test/Dialect/Math/canonicalize.mlir b/mlir/test/Dialect/Math/canonicalize.mlir
index 3459164c5c0a7..6ca81b47a0675 100644
--- a/mlir/test/Dialect/Math/canonicalize.mlir
+++ b/mlir/test/Dialect/Math/canonicalize.mlir
@@ -28,7 +28,7 @@ func.func @log2_fold() -> f32 {
 }
 
 // CHECK-LABEL: @log2_fold2
-// CHECK: %[[cst:.+]] = arith.constant 0xFF800000 : f32
+// CHECK: %[[cst:.+]] = arith.constant -inf : f32
   // CHECK: return %[[cst]]
 func.func @log2_fold2() -> f32 {
   %c = arith.constant 0.0 : f32
@@ -56,7 +56,7 @@ func.func @log2_fold_64() -> f64 {
 }
 
 // CHECK-LABEL: @log2_fold2_64
-// CHECK: %[[cst:.+]] = arith.constant 0xFFF0000000000000 : f64
+// CHECK: %[[cst:.+]] = arith.constant -inf : f64
   // CHECK: return %[[cst]]
 func.func @log2_fold2_64() -> f64 {
   %c = arith.constant 0.0 : f64
diff --git a/mlir/test/Dialect/Math/expand-math.mlir b/mlir/test/Dialect/Math/expand-math.mlir
index 84b0bb0aa314a..973eab6348d66 100644
--- a/mlir/test/Dialect/Math/expand-math.mlir
+++ b/mlir/test/Dialect/Math/expand-math.mlir
@@ -634,8 +634,8 @@ func.func @math_fpowi_neg_odd_power(%0 : tensor<8xf32>) -> tensor<8xf32> {
 //  CHECK-DAG:    %[[CST1:.*]] = arith.constant dense<1.000000e+00> : tensor<8xf32>
 //  CHECK-DAG:    %[[CST0:.*]] = arith.constant dense<0.000000e+00> : tensor<8xf32>
 //  CHECK-DAG:    %[[CSTNEG0:.*]] = arith.constant dense<-0.000000e+00> : tensor<8xf32>
-//  CHECK-DAG:    %[[CSTINF:.*]] = arith.constant dense<0x7F800000> : tensor<8xf32>
-//  CHECK-DAG:    %[[CSTNEGINF:.*]] = arith.constant dense<0xFF800000> : tensor<8xf32>
+//  CHECK-DAG:    %[[CSTINF:.*]] = arith.constant dense<+inf> : tensor<8xf32>
+//  CHECK-DAG:    %[[CSTNEGINF:.*]] = arith.constant dense<-inf> : tensor<8xf32>
 //  CHECK:        %[[SQ:.*]] = arith.mulf %[[ARG0]], %[[ARG0]] : tensor<8xf32>
 //  CHECK:        %[[CUBE:.*]] = arith.mulf %[[SQ]], %[[ARG0]] : tensor<8xf32>
 //  CHECK:        %[[CMP0:.*]] = arith.cmpf oeq, %[[CUBE]], %[[CST0]] : tensor<8xf32>
@@ -657,8 +657,8 @@ func.func @math_fpowi_neg_even_power(%0 : tensor<8xf32>) -> tensor<8xf32> {
 //  CHECK-DAG:    %[[CST1:.*]] = arith.constant dense<1.000000e+00> : tensor<8xf32>
 //  CHECK-DAG:    %[[CST0:.*]] = arith.constant dense<0.000000e+00> : tensor<8xf32>
 //  CHECK-DAG:    %[[CSTNEG0:.*]] = arith.constant dense<-0.000000e+00> : tensor<8xf32>
-//  CHECK-DAG:    %[[CSTINF:.*]] = arith.constant dense<0x7F800000> : tensor<8xf32>
-//  CHECK-DAG:    %[[CSTNEGINF:.*]] = arith.constant dense<0xFF800000> : tensor<8xf32>
+//  CHECK-DAG:    %[[CSTINF:.*]] = arith.constant dense<+inf> : tensor<8xf32>
+//  CHECK-DAG:    %[[CSTNEGINF:.*]] = arith.constant dense<-inf> : tensor<8xf32>
 //  CHECK:        %[[SQ:.*]] = arith.mulf %[[ARG0]], %[[ARG0]] : tensor<8xf32>
 //  CHECK:        %[[PW4:.*]] = arith.mulf %[[SQ]], %[[SQ]] : tensor<8xf32>
 //  CHECK:        %[[CMP0:.*]] = arith.cmpf oeq, %[[PW4]], %[[CST0]] : tensor<8xf32>
diff --git a/mlir/test/Dialect/Math/polynomial-approximation.mlir b/mlir/test/Dialect/Math/polynomial-approximation.mlir
index c14ed47853411..9f447ecd5f497 100644
--- a/mlir/test/Dialect/Math/polynomial-approximation.mlir
+++ b/mlir/test/Dialect/Math/polynomial-approximation.mlir
@@ -114,7 +114,7 @@ func.func @erf_scalar(%arg0: f32) -> f32 {
 // CHECK-DAG:     %[[cst_24:.*]] = arith.constant -4.000000e+00 : f32
 // CHECK-DAG:     %[[cst_25:.*]] = arith.constant -2.000000e+00 : f32
 // CHECK-DAG:     %[[cst_26:.*]] = arith.constant 2.000000e+00 : f32
-// CHECK-DAG:     %[[cst_27:.*]] = arith.constant 0x7F800000 : f32
+// CHECK-DAG:     %[[cst_27:.*]] = arith.constant +inf : f32
 // CHECK-DAG:     %[[cst_28:.*]] = arith.constant 10.0546875 : f32
 // CHECK:         %[[val_2:.*]] = math.absf %[[val_arg0]] : f32
 // CHECK-NEXT:    %[[val_3:.*]] = arith.addf %[[val_2]], %[[cst_26]] : f32
@@ -308,9 +308,9 @@ func.func @exp_scalable_vector(%arg0: vector<[8]xf32>) -> vector<[8]xf32> {
 // CHECK-DAG:       %[[VAL_18:.*]] = arith.constant 0.000000e+00 : f32
 // CHECK-DAG:       %[[VAL_19:.*]] = arith.constant -5.000000e-01 : f32
 // CHECK-DAG:       %[[VAL_20:.*]] = arith.constant 1.17549435E-38 : f32
-// CHECK-DAG:       %[[VAL_21:.*]] = arith.constant 0xFF800000 : f32
-// CHECK-DAG:       %[[VAL_22:.*]] = arith.constant 0x7F800000 : f32
-// CHECK-DAG:       %[[VAL_23:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK-DAG:       %[[VAL_21:.*]] = arith.constant -inf : f32
+// CHECK-DAG:       %[[VAL_22:.*]] = arith.constant +inf : f32
+// CHECK-DAG:       %[[VAL_23:.*]] = arith.constant +qnan : f32
 // CHECK-DAG:       %[[VAL_24:.*]] = arith.constant 0.707106769 : f32
 // CHECK-DAG:       %[[VAL_25:.*]] = arith.constant 0.0703768358 : f32
 // CHECK-DAG:       %[[VAL_26:.*]] = arith.constant -0.115146101 : f32
@@ -434,9 +434,9 @@ func.func @expm1_scalable_vector(%arg0: vector<8x[8]xf32>) -> vector<8x[8]xf32>
 // CHECK-DAG:       %[[VAL_2:.*]] = arith.constant 1.000000e+00 : f32
 // CHECK-DAG:       %[[VAL_3:.*]] = arith.constant -5.000000e-01 : f32
 // CHECK-DAG:       %[[VAL_4:.*]] = arith.constant 1.17549435E-38 : f32
-// CHECK-DAG:       %[[VAL_5:.*]] = arith.constant 0xFF800000 : f32
-// CHECK-DAG:       %[[VAL_6:.*]] = arith.constant 0x7F800000 : f32
-// CHECK-DAG:       %[[VAL_7:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK-DAG:       %[[VAL_5:.*]] = arith.constant -inf : f32
+// CHECK-DAG:       %[[VAL_6:.*]] = arith.constant +inf : f32
+// CHECK-DAG:       %[[VAL_7:.*]] = arith.constant +qnan : f32
 // CHECK-DAG:       %[[VAL_8:.*]] = arith.constant 0.707106769 : f32
 // CHECK-DAG:       %[[VAL_9:.*]] = arith.constant 0.0703768358 : f32
 // CHECK-DAG:       %[[VAL_10:.*]] = arith.constant -0.115146101 : f32
@@ -683,7 +683,7 @@ func.func @rsqrt_scalar(%arg0: f32) -> f32 {
 // CHECK:           math.rsqrt
 // AVX2-LABEL:    func @rsqrt_vector_8xf32(
 // AVX2-SAME:       %[[VAL_0:.*]]: vector<8xf32>) -> vector<8xf32> {
-// AVX2:   %[[VAL_1:.*]] = arith.constant dense<0x7F800000> : vector<8xf32>
+// AVX2:   %[[VAL_1:.*]] = arith.constant dense<+inf> : vector<8xf32>
 // AVX2:   %[[VAL_2:.*]] = arith.constant dense<1.500000e+00> : vector<8xf32>
 // AVX2:   %[[VAL_3:.*]] = arith.constant dense<-5.000000e-01> : vector<8xf32>
 // AVX2:   %[[VAL_4:.*]] = arith.constant dense<1.17549435E-38> : vector<8xf32>
@@ -857,7 +857,7 @@ func.func @atan_scalar(%arg0: f32) -> f32 {
 // CHECK-DAG:       %[[VAL_17:.*]] = arith.constant 0.000000e+00 : f32
 // CHECK-DAG:       %[[VAL_18:.*]] = arith.constant 3.14159274 : f32
 // CHECK-DAG:       %[[VAL_19:.*]] = arith.constant -1.57079637 : f32
-// CHECK-DAG:       %[[VAL_20:.*]] = arith.constant 0x7FC00000 : f32
+// CHECK-DAG:       %[[VAL_20:.*]] = arith.constant +qnan : f32
 // CHECK-DAG:       %[[VAL_21:.*]] = arith.extf %[[VAL_0]] : f16 to f32
 // CHECK-DAG:       %[[VAL_22:.*]] = arith.extf %[[VAL_1]] : f16 to f32
 // CHECK-DAG:       %[[VAL_23:.*]] = arith.divf %[[VAL_21]], %[[VAL_22]] : f32
diff --git a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
index 37a9e97106de9..134ea627cf165 100644
--- a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
@@ -177,7 +177,7 @@ func.func @struct_constant_identified() -> () {
 // -----
 
 func.func @coop_matrix_const_non_dense() -> () {
-    // expected-error @+2 {{floating point value not valid for specified type}}
+    // expected-error @below {{floating point value not valid for specified type}}
     %0 = spirv.Constant 0.000000e+00 : !spirv.coopmatrix<16x16xf32, Subgroup, MatrixAcc>
     return
 }
diff --git a/mlir/test/Dialect/Tosa/constant-reciprocal-fold.mlir b/mlir/test/Dialect/Tosa/constant-reciprocal-fold.mlir
index 12a3aee428ac6..e17e1b09e9e2e 100644
--- a/mlir/test/Dialect/Tosa/constant-reciprocal-fold.mlir
+++ b/mlir/test/Dialect/Tosa/constant-reciprocal-fold.mlir
@@ -22,8 +22,8 @@ func.func @reciprocal_fold_splat() -> tensor<12x7xf32> {
 
 // CHECK-LABEL: @reciprocal_div_zero
 func.func @reciprocal_div_zero() -> tensor<f32> {
-  // 0x7F800000 is the value for +infinity
-  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}0x7F800000
+  // +inf is the value for +infinity
+  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}+inf
   // CHECK-NOT: tosa.reciprocal
   // CHECK: return [[RES]]
   %0 = "tosa.const"() {values = dense<0.0> : tensor<f32>} : () -> tensor<f32>
@@ -33,8 +33,8 @@ func.func @reciprocal_div_zero() -> tensor<f32> {
 
 // CHECK-LABEL: @reciprocal_div_neg_zero
 func.func @reciprocal_div_neg_zero() -> tensor<f32> {
-  // 0xFF800000 is the value for -infinity
-  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}0xFF800000
+  // -inf is the value for -infinity
+  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}-inf
   // CHECK-NOT: tosa.reciprocal
   // CHECK: return [[RES]]
   %0 = "tosa.const"() {values = dense<-0.0> : tensor<f32>} : () -> tensor<f32>
@@ -44,8 +44,8 @@ func.func @reciprocal_div_neg_zero() -> tensor<f32> {
 
 // CHECK-LABEL: @reciprocal_div_nan
 func.func @reciprocal_div_nan() -> tensor<f32> {
-  // 0x7FC00000 is the value for NAN
-  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}0x7FC00000
+  // +qnan is the value for NAN
+  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}+qnan
   // CHECK-NOT: tosa.reciprocal
   // CHECK: return [[RES]]
   %0 = "tosa.const"() {values = dense<0x7FC00000> : tensor<f32>} : () -> tensor<f32>
@@ -85,7 +85,7 @@ func.func @reciprocal_div_underflow() -> tensor<2xf16> {
 
 // CHECK-LABEL: @reciprocal_div_overflow
 func.func @reciprocal_div_overflow() -> tensor<2xf16> {
-  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}0x7C00, 0xFC00
+  // CHECK: [[RES:]] ={{.*}}tosa.const{{.*}}+inf, -inf
   // CHECK-NOT: tosa.reciprocal
   // CHECK: return [[RES]]
   %0 = "tosa.const"() {values = dense<[0.0000001, -0.0000001]> : tensor<2xf16>} : () -> tensor<2xf16>
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index e559ea5f3c0ab..26ac36f89e1f1 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -2019,7 +2019,7 @@ func.func @test_mul_out_i16(%arg0: tensor<13x21x3xi8>, %arg1: tensor<13x1x3xi8>,
 
 // CHECK-LABEL: test_clamp_nan_min_val
 func.func @test_clamp_nan_min_val(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3xf32> {
-  // expected-error at +1 {{'tosa.clamp' op min/max attributes should not be 'NaN', got min_val=0xFFFFFFFF : f32, max_val=1.000000e+00 : f32}}
+  // expected-error at +1 {{'tosa.clamp' op min/max attributes should not be 'NaN', got min_val=-nan(0x3FFFFF) : f32, max_val=1.000000e+00 : f32}}
   %0 = tosa.clamp %arg0 {min_val = 0xFFFFFFFF : f32, max_val = 1.0: f32} : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
   return %0 : tensor<13x21x3xf32>
 }
@@ -2028,7 +2028,7 @@ func.func @test_clamp_nan_min_val(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3x
 
 // CHECK-LABEL: test_clamp_nan_max_val
 func.func @test_clamp_nan_max_val(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3xf32> {
-  // expected-error at +1 {{'tosa.clamp' op min/max attributes should not be 'NaN', got min_val=2.300000e+00 : f32, max_val=0x7FFFFFFF : f32}}
+  // expected-error at +1 {{'tosa.clamp' op min/max attributes should not be 'NaN', got min_val=2.300000e+00 : f32, max_val=+nan(0x3FFFFF) : f32}}
   %0 = tosa.clamp %arg0 {min_val = 2.3 : f32, max_val = 0x7FFFFFFF: f32} : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
   return %0 : tensor<13x21x3xf32>
 }
diff --git a/mlir/test/Dialect/XeGPU/propagate-layout.mlir b/mlir/test/Dialect/XeGPU/propagate-layout.mlir
index 79a5d229263c5..ceb8123329cdb 100644
--- a/mlir/test/Dialect/XeGPU/propagate-layout.mlir
+++ b/mlir/test/Dialect/XeGPU/propagate-layout.mlir
@@ -776,7 +776,7 @@ func.func @vector_2d_reduction_with_fractional_subgroup_size_1x4(%arg0: memref<1
 gpu.module @test {
 // CHECK: func.func @vector_reduction_broadcast_transpose(%[[ARG0:.*]]: memref<1024x64xf32>, %[[ARG1:.*]]: memref<1024x64xf32>)
 // CHECK: %[[CST:.*]] = arith.constant {layout_result_0 = #xegpu.slice<#xegpu.layout<lane_layout = [1, 16], lane_data = [1, 1]>, dims = [1]>} dense<0.000000e+00> : vector<1xf32>
-// CHECK: %[[CST_0:.*]] = arith.constant {layout_result_0 = #xegpu.layout<lane_layout = [1, 16], lane_data = [1, 1]>} dense<0xFF800000> : vector<1x16xf32>
+// CHECK: %[[CST_0:.*]] = arith.constant {layout_result_0 = #xegpu.layout<lane_layout = [1, 16], lane_data = [1, 1]>} dense<-inf> : vector<1x16xf32>
 // CHECK: %[[CST_1:.*]] = arith.constant {layout_result_0 = #xegpu.slice<#xegpu.layout<lane_layout = [16, 1], lane_data = [1, 1], order = [0, 1]>, dims = [0]>} dense<0.000000e+00> : vector<8xf32>
 // CHECK: %[[C0:.*]] = arith.constant 0 : index
 // CHECK: %[[RED:.*]] = vector.multi_reduction <add>, %[[CST_0]], %[[CST]] {layout_result_0 = #xegpu.slice<#xegpu.layout<lane_layout = [1, 16], lane_data = [1, 1]>, dims = [1]>} [1] : vector<1x16xf32> to vector<1xf32>
diff --git a/mlir/test/IR/array-of-attr.mlir b/mlir/test/IR/array-of-attr.mlir
index 2c7b5009f74a2..96f7207170394 100644
--- a/mlir/test/IR/array-of-attr.mlir
+++ b/mlir/test/IR/array-of-attr.mlir
@@ -14,5 +14,5 @@ test.array_of_attr_op
 test.array_of_attr_op a = [], b = [], c = []
 
 // CHECK: "test.test_array_float"
-// CHECK-SAME: 1.000000e+00 : f32, 1.000000e+00, 0x7FF0000000000000 : f64
+// CHECK-SAME: 1.000000e+00 : f32, 1.000000e+00, +inf : f64
 "test.test_array_float"() {test.float_arr = [1.0 : f32, 1.0 : f64, 0x7FF0000000000000 : f64]} : () -> ()
diff --git a/mlir/test/IR/custom-float-attr-roundtrip.mlir b/mlir/test/IR/custom-float-attr-roundtrip.mlir
index a8da89ba7372d..5cf82f493a7f8 100644
--- a/mlir/test/IR/custom-float-attr-roundtrip.mlir
+++ b/mlir/test/IR/custom-float-attr-roundtrip.mlir
@@ -8,11 +8,11 @@ func.func @test_enum_attr_roundtrip() -> () {
   "test.op"() {attr = #test.custom_float<"double" : 2.>} : () -> ()
    // CHECK: attr = #test.custom_float<"fp80" : 2.000000e+00>
   "test.op"() {attr = #test.custom_float<"fp80" : 2.>} : () -> ()
-  // CHECK: attr = #test.custom_float<"float" : 0x7FC00000>
+  // CHECK: attr = #test.custom_float<"float" : +qnan>
   "test.op"() {attr = #test.custom_float<"float" : 0x7FC00000>} : () -> ()
-  // CHECK: attr = #test.custom_float<"double" : 0x7FF0000001000000>
+  // CHECK: attr = #test.custom_float<"double" : +snan(0x1000000)>
   "test.op"() {attr = #test.custom_float<"double" : 0x7FF0000001000000>} : () -> ()
-  // CHECK: attr = #test.custom_float<"fp80" : 0x7FFFC000000000100000>
+  // CHECK: attr = #test.custom_float<"fp80" : +nan(0x100000)>
   "test.op"() {attr = #test.custom_float<"fp80" : 0x7FFFC000000000100000>} : () -> ()
   return
 }
diff --git a/mlir/test/IR/float-literals-hex.mlir b/mlir/test/IR/float-literals-hex.mlir
new file mode 100644
index 0000000000000..601ea62e7ad6e
--- /dev/null
+++ b/mlir/test/IR/float-literals-hex.mlir
@@ -0,0 +1,50 @@
+// RUN: mlir-opt %s --mlir-print-float-special-literals-as-hex | FileCheck %s --check-prefix=HEX
+// RUN: mlir-opt %s --mlir-print-float-special-literals-as-hex | mlir-opt | FileCheck %s --check-prefix=ROUNDTRIP
+
+// The --mlir-print-float-special-literals-as-hex flag prints infinities and NaNs as a
+// hexadecimal bit pattern (the legacy form). The parser still accepts both the
+// hex and the human-readable spellings, so the hex output round-trips back to
+// the human-readable form.
+
+// HEX-LABEL: @infinities
+// ROUNDTRIP-LABEL: @infinities
+func.func @infinities() {
+  // HEX: arith.constant 0x7F800000 : f32
+  // ROUNDTRIP: arith.constant +inf : f32
+  %0 = arith.constant +inf : f32
+  // HEX: arith.constant 0xFF800000 : f32
+  // ROUNDTRIP: arith.constant -inf : f32
+  %1 = arith.constant -inf : f32
+  // HEX: arith.constant 0x7FF0000000000000 : f64
+  // ROUNDTRIP: arith.constant +inf : f64
+  %2 = arith.constant +inf : f64
+  return
+}
+
+// HEX-LABEL: @nans
+// ROUNDTRIP-LABEL: @nans
+func.func @nans() {
+  // HEX: arith.constant 0x7FC00000 : f32
+  // ROUNDTRIP: arith.constant +qnan : f32
+  %0 = arith.constant +qnan : f32
+  // HEX: arith.constant 0xFFF8000000000000 : f64
+  // ROUNDTRIP: arith.constant -qnan : f64
+  %1 = arith.constant -qnan : f64
+  // HEX: arith.constant 0x7FC00001 : f32
+  // ROUNDTRIP: arith.constant +nan(0x1) : f32
+  %2 = arith.constant +nan(0x1) : f32
+  // HEX: arith.constant 0x7FF0000000000001 : f64
+  // ROUNDTRIP: arith.constant +snan(0x1) : f64
+  %3 = arith.constant +snan(0x1) : f64
+  return
+}
+
+// Special values also print as hex inside dense elements attributes.
+// HEX-LABEL: @special_values_in_elements
+// ROUNDTRIP-LABEL: @special_values_in_elements
+func.func @special_values_in_elements() {
+  // HEX: dense<[0x7F800000, 0xFF800000, 0x7FC00000]> : tensor<3xf32>
+  // ROUNDTRIP: dense<[+inf, -inf, +qnan]> : tensor<3xf32>
+  %0 = arith.constant dense<[+inf, -inf, +qnan]> : tensor<3xf32>
+  return
+}
diff --git a/mlir/test/IR/float-literals.mlir b/mlir/test/IR/float-literals.mlir
new file mode 100644
index 0000000000000..d26ad638eeb13
--- /dev/null
+++ b/mlir/test/IR/float-literals.mlir
@@ -0,0 +1,117 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// Human-readable floating point special values and C-style hexadecimal floats,
+// as accepted by the parser and produced by the printer.
+
+// CHECK-LABEL: @infinities
+func.func @infinities() {
+  // CHECK: arith.constant +inf : f32
+  %0 = arith.constant +inf : f32
+  // CHECK: arith.constant -inf : f32
+  %1 = arith.constant -inf : f32
+  // CHECK: arith.constant +inf : f64
+  %2 = arith.constant +inf : f64
+  // CHECK: arith.constant -inf : f16
+  %3 = arith.constant -inf : f16
+  // CHECK: arith.constant +inf : bf16
+  %4 = arith.constant +inf : bf16
+  return
+}
+
+// CHECK-LABEL: @quiet_nans
+func.func @quiet_nans() {
+  // CHECK: arith.constant +qnan : f32
+  %0 = arith.constant +qnan : f32
+  // CHECK: arith.constant -qnan : f64
+  %1 = arith.constant -qnan : f64
+  // CHECK: arith.constant +qnan : f16
+  %2 = arith.constant +qnan : f16
+  // CHECK: arith.constant -qnan : bf16
+  %3 = arith.constant -qnan : bf16
+  return
+}
+
+// CHECK-LABEL: @nan_payloads
+func.func @nan_payloads() {
+  // CHECK: arith.constant +nan(0x1) : f32
+  %0 = arith.constant +nan(0x1) : f32
+  // CHECK: arith.constant -nan(0x3FFFFF) : f32
+  %1 = arith.constant -nan(0x3FFFFF) : f32
+  // CHECK: arith.constant +snan(0x1) : f64
+  %2 = arith.constant +snan(0x1) : f64
+  // CHECK: arith.constant -snan(0x1000000) : f64
+  %3 = arith.constant -snan(0x1000000) : f64
+  return
+}
+
+// CHECK-LABEL: @hex_floats
+func.func @hex_floats() {
+  // 0x1.8p3 == 1.5 * 2^3 == 12.0; the exponent sign and 'p'/'P' case may vary.
+  // CHECK: arith.constant 1.200000e+01 : f64
+  %0 = arith.constant 0x1.8p3 : f64
+  // CHECK: arith.constant 1.200000e+01 : f64
+  %1 = arith.constant 0x1.8p+3 : f64
+  // CHECK: arith.constant 1.200000e+01 : f64
+  %2 = arith.constant 0x1.8P3 : f64
+  // CHECK: arith.constant -1.200000e+01 : f64
+  %3 = arith.constant -0x1.8p3 : f64
+  // 0x1.8p-3 == 1.5 * 2^-3 == 0.1875
+  // CHECK: arith.constant 1.875000e-01 : f64
+  %4 = arith.constant 0x1.8p-3 : f64
+  // No fractional part.
+  // CHECK: arith.constant 1.600000e+01 : f32
+  %5 = arith.constant 0x1p4 : f32
+  // CHECK: arith.constant 0.000000e+00 : f32
+  %6 = arith.constant 0x0p0 : f32
+  // Built directly in the (wider than double) target semantics.
+  // CHECK: arith.constant 1.200000e+01 : f80
+  %7 = arith.constant 0x1.8p3 : f80
+  // CHECK: arith.constant 1.200000e+01 : f128
+  %8 = arith.constant 0x1.8p3 : f128
+  // A value that needs full precision to round-trip.
+  // CHECK: arith.constant 3.1415926535897931 : f64
+  %9 = arith.constant 0x1.921fb54442d18p1 : f64
+  return
+}
+
+// CHECK-LABEL: @special_values_in_elements
+func.func @special_values_in_elements() {
+  // CHECK: dense<[+inf, -inf, +qnan]> : tensor<3xf32>
+  %0 = arith.constant dense<[+inf, -inf, +qnan]> : tensor<3xf32>
+  // A splat built from a single special value.
+  // CHECK: dense<-inf> : tensor<4xf64>
+  %1 = arith.constant dense<-inf> : tensor<4xf64>
+  return
+}
+
+// Low-precision and other builtin float types on the special-value path.
+// CHECK-LABEL: @low_precision_and_other_types
+func.func @low_precision_and_other_types() {
+  // f8E8M0FNU has zero mantissa bits: its NaN prints as the canonical qnan.
+  // CHECK: arith.constant +qnan : f8E8M0FNU
+  %0 = arith.constant +qnan : f8E8M0FNU
+  // Payload wider than the mantissa is masked (f8E5M2 keeps 1 payload bit).
+  // CHECK: arith.constant +nan(0x1) : f8E5M2
+  %1 = arith.constant +nan(0x7) : f8E5M2
+  // FNUZ formats have a single NaN encoding; a signaling request collapses to it.
+  // CHECK: arith.constant -nan(0x0) : f8E4M3FNUZ
+  %2 = arith.constant +snan(0x1) : f8E4M3FNUZ
+  // CHECK: arith.constant +inf : tf32
+  %3 = arith.constant +inf : tf32
+  return
+}
+
+// Payload spelling normalizations and overflow tolerance.
+// CHECK-LABEL: @nan_payload_and_overflow
+func.func @nan_payload_and_overflow() {
+  // A zero payload normalizes to the canonical quiet NaN.
+  // CHECK: arith.constant +qnan : f32
+  %0 = arith.constant +nan(0x0) : f32
+  // An unprefixed payload is decimal; it prints back as hex.
+  // CHECK: arith.constant +nan(0xA) : f32
+  %1 = arith.constant +nan(10) : f32
+  // Decimal overflow saturates to infinity rather than erroring.
+  // CHECK: arith.constant +inf : f16
+  %2 = arith.constant 1.0e40 : f16
+  return
+}
diff --git a/mlir/test/IR/invalid-builtin-attributes.mlir b/mlir/test/IR/invalid-builtin-attributes.mlir
index 0d00b3141fbc6..03a25f43f09b7 100644
--- a/mlir/test/IR/invalid-builtin-attributes.mlir
+++ b/mlir/test/IR/invalid-builtin-attributes.mlir
@@ -52,6 +52,16 @@ func.func @elementsattr_floattype2() -> () {
 
 // -----
 
+// The diagnostic must point at the float literal, not the following token
+// (the `}` is on the next line, exposing a stale location).
+func.func @float_attr_non_float_type() -> () {
+  // expected-error at below {{floating point value not valid for specified type}}
+  "foo"(){bar = 1.0 : i32
+  } : () -> ()
+}
+
+// -----
+
 func.func @elementsattr_toolarge1() -> () {
   "foo"(){bar = dense<[777]> : tensor<1xi8>} : () -> () // expected-error {{integer constant out of range}}
 }
@@ -675,3 +685,88 @@ func.func @expect_to_parse_literal() {
   %0 = arith.constant dense<[23]> : tensor<1x!unknown<>>
   return
 }
+
+// -----
+
+func.func @hex_float_without_exponent() {
+  // expected-error at below {{expected binary exponent in hexadecimal floating point literal}}
+  %0 = arith.constant 0x1.8 : f64
+  return
+}
+
+// -----
+
+func.func @hex_float_missing_exponent_digits() {
+  // expected-error at below {{expected binary exponent in hexadecimal floating point literal}}
+  %0 = arith.constant 0x1.0p : f64
+  return
+}
+
+// -----
+
+func.func @unclosed_nan_literal() {
+  // expected-error at below {{expected ')' in NaN literal}}
+  %0 = arith.constant +nan(0x1 : f32
+  return
+}
+
+// -----
+
+func.func @invalid_nan_payload() {
+  // expected-error at below {{invalid floating point literal}}
+  %0 = arith.constant +nan(0xZZ) : f32
+  return
+}
+
+// -----
+
+func.func @inf_on_integer_type() {
+  // expected-error at below {{floating point value not valid for specified type}}
+  %0 = arith.constant +inf : i32
+  return
+}
+
+// -----
+
+func.func @doubly_signed_inf() {
+  // Doubly-signed literal: a '-' token before an already-signed inf/NaN.
+  // expected-error at below {{floating point literal has more than one sign}}
+  %0 = arith.constant -+inf : f64
+  return
+}
+
+// -----
+
+func.func @inf_on_type_without_inf() {
+  // f4E2M1FN has no Inf encoding: reject, do not crash APFloat.
+  // expected-error at below {{floating point type does not support infinity}}
+  %0 = arith.constant +inf : f4E2M1FN
+  return
+}
+
+// -----
+
+func.func @nan_on_type_without_nan() {
+  // f6E2M3FN has no NaN encoding.
+  // expected-error at below {{floating point type does not support NaN}}
+  %0 = arith.constant +qnan : f6E2M3FN
+  return
+}
+
+// -----
+
+func.func @inf_on_nan_only_type() {
+  // f8E4M3FN has NaN but no Inf.
+  // expected-error at below {{floating point type does not support infinity}}
+  %0 = arith.constant +inf : f8E4M3FN
+  return
+}
+
+// -----
+
+func.func @negative_on_unsigned_type() {
+  // f8E8M0FNU is unsigned: reject negatives, do not crash the printer.
+  // expected-error at below {{floating point type does not support negative values}}
+  %0 = arith.constant -1.0 : f8E8M0FNU
+  return
+}
diff --git a/mlir/test/IR/parser.mlir b/mlir/test/IR/parser.mlir
index e10dbf36e2797..1375c4edb11d0 100644
--- a/mlir/test/IR/parser.mlir
+++ b/mlir/test/IR/parser.mlir
@@ -1022,18 +1022,18 @@ func.func @dialect_attribute_with_type() {
 // CHECK-LABEL: @f16_special_values
 func.func @f16_special_values() {
   // F16 NaNs.
-  // CHECK: arith.constant 0x7C01 : f16
+  // CHECK: arith.constant +snan(0x1) : f16
   %0 = arith.constant 0x7C01 : f16
-  // CHECK: arith.constant 0x7FFF : f16
+  // CHECK: arith.constant +nan(0x1FF) : f16
   %1 = arith.constant 0x7FFF : f16
-  // CHECK: arith.constant 0xFFFF : f16
+  // CHECK: arith.constant -nan(0x1FF) : f16
   %2 = arith.constant 0xFFFF : f16
 
   // F16 positive infinity.
-  // CHECK: arith.constant 0x7C00 : f16
+  // CHECK: arith.constant +inf : f16
   %3 = arith.constant 0x7C00 : f16
   // F16 negative infinity.
-  // CHECK: arith.constant 0xFC00 : f16
+  // CHECK: arith.constant -inf : f16
   %4 = arith.constant 0xFC00 : f16
 
   return
@@ -1042,22 +1042,22 @@ func.func @f16_special_values() {
 // CHECK-LABEL: @f32_special_values
 func.func @f32_special_values() {
   // F32 signaling NaNs.
-  // CHECK: arith.constant 0x7F800001 : f32
+  // CHECK: arith.constant +snan(0x1) : f32
   %0 = arith.constant 0x7F800001 : f32
-  // CHECK: arith.constant 0x7FBFFFFF : f32
+  // CHECK: arith.constant +snan(0x3FFFFF) : f32
   %1 = arith.constant 0x7FBFFFFF : f32
 
   // F32 quiet NaNs.
-  // CHECK: arith.constant 0x7FC00000 : f32
+  // CHECK: arith.constant +qnan : f32
   %2 = arith.constant 0x7FC00000 : f32
-  // CHECK: arith.constant 0xFFFFFFFF : f32
+  // CHECK: arith.constant -nan(0x3FFFFF) : f32
   %3 = arith.constant 0xFFFFFFFF : f32
 
   // F32 positive infinity.
-  // CHECK: arith.constant 0x7F800000 : f32
+  // CHECK: arith.constant +inf : f32
   %4 = arith.constant 0x7F800000 : f32
   // F32 negative infinity.
-  // CHECK: arith.constant 0xFF800000 : f32
+  // CHECK: arith.constant -inf : f32
   %5 = arith.constant 0xFF800000 : f32
 
   return
@@ -1066,22 +1066,22 @@ func.func @f32_special_values() {
 // CHECK-LABEL: @f64_special_values
 func.func @f64_special_values() {
   // F64 signaling NaNs.
-  // CHECK: arith.constant 0x7FF0000000000001 : f64
+  // CHECK: arith.constant +snan(0x1) : f64
   %0 = arith.constant 0x7FF0000000000001 : f64
-  // CHECK: arith.constant 0x7FF8000000000000 : f64
+  // CHECK: arith.constant +qnan : f64
   %1 = arith.constant 0x7FF8000000000000 : f64
 
   // F64 quiet NaNs.
-  // CHECK: arith.constant 0x7FF0000001000000 : f64
+  // CHECK: arith.constant +snan(0x1000000) : f64
   %2 = arith.constant 0x7FF0000001000000 : f64
-  // CHECK: arith.constant 0xFFF0000001000000 : f64
+  // CHECK: arith.constant -snan(0x1000000) : f64
   %3 = arith.constant 0xFFF0000001000000 : f64
 
   // F64 positive infinity.
-  // CHECK: arith.constant 0x7FF0000000000000 : f64
+  // CHECK: arith.constant +inf : f64
   %4 = arith.constant 0x7FF0000000000000 : f64
   // F64 negative infinity.
-  // CHECK: arith.constant 0xFFF0000000000000 : f64
+  // CHECK: arith.constant -inf : f64
   %5 = arith.constant 0xFFF0000000000000 : f64
 
   // Check that values that can't be represented with the default format, use
@@ -1095,22 +1095,22 @@ func.func @f64_special_values() {
 // CHECK-LABEL: @bfloat16_special_values
 func.func @bfloat16_special_values() {
   // bfloat16 signaling NaNs.
-  // CHECK: arith.constant 0x7F81 : bf16
+  // CHECK: arith.constant +snan(0x1) : bf16
   %0 = arith.constant 0x7F81 : bf16
-  // CHECK: arith.constant 0xFF81 : bf16
+  // CHECK: arith.constant -snan(0x1) : bf16
   %1 = arith.constant 0xFF81 : bf16
 
   // bfloat16 quiet NaNs.
-  // CHECK: arith.constant 0x7FC0 : bf16
+  // CHECK: arith.constant +qnan : bf16
   %2 = arith.constant 0x7FC0 : bf16
-  // CHECK: arith.constant 0xFFC0 : bf16
+  // CHECK: arith.constant -qnan : bf16
   %3 = arith.constant 0xFFC0 : bf16
 
   // bfloat16 positive infinity.
-  // CHECK: arith.constant 0x7F80 : bf16
+  // CHECK: arith.constant +inf : bf16
   %4 = arith.constant 0x7F80 : bf16
   // bfloat16 negative infinity.
-  // CHECK: arith.constant 0xFF80 : bf16
+  // CHECK: arith.constant -inf : bf16
   %5 = arith.constant 0xFF80 : bf16
 
   return
@@ -1119,22 +1119,22 @@ func.func @bfloat16_special_values() {
 // CHECK-LABEL: @f80_special_values
 func.func @f80_special_values() {
   // F80 signaling NaNs.
-  // CHECK: arith.constant 0x7FFFE000000000000001 : f80
+  // CHECK: arith.constant +nan(0x2000000000000001) : f80
   %0 = arith.constant 0x7FFFE000000000000001 : f80
-  // CHECK: arith.constant 0x7FFFB000000000000011 : f80
+  // CHECK: arith.constant +snan(0x3000000000000011) : f80
   %1 = arith.constant 0x7FFFB000000000000011 : f80
 
   // F80 quiet NaNs.
-  // CHECK: arith.constant 0x7FFFC000000000100000 : f80
+  // CHECK: arith.constant +nan(0x100000) : f80
   %2 = arith.constant 0x7FFFC000000000100000 : f80
-  // CHECK: arith.constant 0x7FFFE000000001000000 : f80
+  // CHECK: arith.constant +nan(0x2000000001000000) : f80
   %3 = arith.constant 0x7FFFE000000001000000 : f80
 
   // F80 positive infinity.
-  // CHECK: arith.constant 0x7FFF8000000000000000 : f80
+  // CHECK: arith.constant +inf : f80
   %4 = arith.constant 0x7FFF8000000000000000 : f80
   // F80 negative infinity.
-  // CHECK: arith.constant 0xFFFF8000000000000000 : f80
+  // CHECK: arith.constant -inf : f80
   %5 = arith.constant 0xFFFF8000000000000000 : f80
 
   return
@@ -1152,14 +1152,14 @@ func.func @f32_potential_precision_loss() {
 
 // CHECK-LABEL: @special_float_values_in_tensors
 func.func @special_float_values_in_tensors() {
-  // CHECK: dense<0xFFFFFFFF> : tensor<4x4xf32>
+  // CHECK: dense<-nan(0x3FFFFF)> : tensor<4x4xf32>
   "foo"(){bar = dense<0xFFFFFFFF> : tensor<4x4xf32>} : () -> ()
-  // CHECK: dense<[{{\[}}0xFFFFFFFF, 0x7F800000], [0x7FBFFFFF, 0x7F800001]]> : tensor<2x2xf32>
+  // CHECK: dense<[{{\[}}-nan(0x3FFFFF), +inf], [+snan(0x3FFFFF), +snan(0x1)]]> : tensor<2x2xf32>
   "foo"(){bar = dense<[[0xFFFFFFFF, 0x7F800000], [0x7FBFFFFF, 0x7F800001]]> : tensor<2x2xf32>} : () -> ()
-  // CHECK: dense<[0xFFFFFFFF, 0.000000e+00]> : tensor<2xf32>
+  // CHECK: dense<[-nan(0x3FFFFF), 0.000000e+00]> : tensor<2xf32>
   "foo"(){bar = dense<[0xFFFFFFFF, 0.0]> : tensor<2xf32>} : () -> ()
 
-  // CHECK: sparse<[{{\[}}1, 1, 0], [0, 1, 1]], [0xFFFFFFFF, 0x7F800001]>
+  // CHECK: sparse<[{{\[}}1, 1, 0], [0, 1, 1]], [-nan(0x3FFFFF), +snan(0x1)]>
   "foo"(){bar = sparse<[[1,1,0],[0,1,1]], [0xFFFFFFFF, 0x7F800001]> : tensor<2x2x2xf32>} : () -> ()
 }
 



More information about the flang-commits mailing list