[llvm] [IR][AsmParser] Revamp how floating-point literals work in LLVM IR. (PR #121838)

Joshua Cranmer via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 14 13:48:14 PST 2025


https://github.com/jcranmer-intel updated https://github.com/llvm/llvm-project/pull/121838

>From c78c9537024ab73bbba546600fd038e1e33d1539 Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Mon, 6 Jan 2025 13:14:33 -0800
Subject: [PATCH 1/6] [AsmParser] Revamp how floating-point literals work in
 LLVM IR.

This adds support for the following kinds of formats:
* Hexadecimal literals like 0x1.fp13
* Special values +inf/-inf, +qnan/-qnan
* NaN values with payloads like +nan(0x1)

Additionally, the floating-point hexadecimal format that records the
bitpattern exactly no longer requires the 0xL or 0xK or similar code for
the floating-point type. This format is removed from the documentation,
but is still supported as a legacy format in the parser.
---
 llvm/docs/LangRef.rst                      |  67 +++----
 llvm/include/llvm/AsmParser/LLLexer.h      |   1 +
 llvm/include/llvm/AsmParser/LLToken.h      |   2 +
 llvm/lib/AsmParser/LLLexer.cpp             | 196 +++++++++++++++++----
 llvm/lib/AsmParser/LLParser.cpp            |  34 +++-
 llvm/lib/CodeGen/MIRParser/MILexer.cpp     |  18 ++
 llvm/lib/Support/APFloat.cpp               |   2 +-
 llvm/test/Assembler/float-literals.ll      |  40 +++++
 llvm/unittests/AsmParser/AsmParserTest.cpp |  47 +++++
 9 files changed, 337 insertions(+), 70 deletions(-)
 create mode 100644 llvm/test/Assembler/float-literals.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 8cc9036d1b67f6..2f874d1eecaffb 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4595,11 +4595,13 @@ Simple Constants
     zeros. So '``s0x0001``' of type '``i16``' will be -1, not 1.
 **Floating-point constants**
     Floating-point constants use standard decimal notation (e.g.
-    123.421), exponential notation (e.g. 1.23421e+2), or a more precise
-    hexadecimal notation (see below). The assembler requires the exact
-    decimal value of a floating-point constant. For example, the
-    assembler accepts 1.25 but rejects 1.3 because 1.3 is a repeating
-    decimal in binary. Floating-point constants must have a
+    123.421), exponential notation (e.g. 1.23421e+2), standard hexadecimal
+    notation (e.g., 0x1.3effp-43), one of several special values, or a
+    precise bitstring for the underlying value. When converting decimal and
+    hexadecimal literals to the floating-point type, the value is converted
+    using the default rounding mode (round to nearest, half to even). String
+    conversions that underflow to 0 or overflow to infinity are not permitted.
+    Floating-point constants must have a
     :ref:`floating-point <t_floating>` type.
 **Null pointer constants**
     The identifier '``null``' is recognized as a null pointer constant
@@ -4608,31 +4610,36 @@ Simple Constants
     The identifier '``none``' is recognized as an empty token constant
     and must be of :ref:`token type <t_token>`.
 
-The one non-intuitive notation for constants is the hexadecimal form of
-floating-point constants. For example, the form
-'``double    0x432ff973cafa8000``' is equivalent to (but harder to read
-than) '``double 4.5e+15``'. The only time hexadecimal floating-point
-constants are required (and the only time that they are generated by the
-disassembler) is when a floating-point constant must be emitted but it
-cannot be represented as a decimal floating-point number in a reasonable
-number of digits. For example, NaN's, infinities, and other special
-values are represented in their IEEE hexadecimal format so that assembly
-and disassembly do not cause any bits to change in the constants.
-
-When using the hexadecimal form, constants of types bfloat, half, float, and
-double are represented using the 16-digit form shown above (which matches the
-IEEE754 representation for double); bfloat, half and float values must, however,
-be exactly representable as bfloat, IEEE 754 half, and IEEE 754 single
-precision respectively. Hexadecimal format is always used for long double, and
-there are three forms of long double. The 80-bit format used by x86 is
-represented as ``0xK`` followed by 20 hexadecimal digits. The 128-bit format
-used by PowerPC (two adjacent doubles) is represented by ``0xM`` followed by 32
-hexadecimal digits. The IEEE 128-bit format is represented by ``0xL`` followed
-by 32 hexadecimal digits. Long doubles will only work if they match the long
-double format on your target.  The IEEE 16-bit format (half precision) is
-represented by ``0xH`` followed by 4 hexadecimal digits. The bfloat 16-bit
-format is represented by ``0xR`` followed by 4 hexadecimal digits. All
-hexadecimal formats are big-endian (sign bit at the left).
+Floating-point constants support the following kinds of strings:
+
+   +---------------+---------------------------------------------------+
+   | Syntax        | Description                                       |
+   +===============+===================================================+
+   | ``+4.5e-13``  | Common decimal literal. Signs are optional, as is |
+   |               | the exponent portion. The decimal point is        |
+   |               | required, as is one or more leading digits before |
+   |               | the decimal point.                                |
+   +---------------+---------------------------------------------------+
+   | ``-0x1.fp13`` | Common hexadecimal literal. Signs are optional.   |
+   |               | The decimal point is required, as is the exponent |
+   |               | portion of the literal (after the ``p``).         |
+   +---------------+---------------------------------------------------+
+   | ``+inf``,     | Positive or negative infinity. The sign is        |
+   | ``-inf``      | required.                                         |
+   +---------------+---------------------------------------------------+
+   | ``+qnan``,    | Positive or negative preferred quiet NaN, i.e.,   |
+   | ``-qnan``     | the quiet bit is set, and all other payload bits  |
+   |               | are 0. The sign is required.                      |
+   +---------------+---------------------------------------------------+
+   | ``+nan(0x1)`` | NaN value with a particular payload, specified as |
+   |               | hexadecimal (including the quiet bit as part of   |
+   |               | the payload). The sign is required.               |
+   +---------------+---------------------------------------------------+
+   | ``f0x3c00``   | Value of the floating-point number if bitcast to  |
+   |               | an integer. The number must have exactly as many  |
+   |               | hexadecimal digits as is necessary for the size   |
+   |               | of the floating-point number.                     |
+   +---------------+---------------------------------------------------+
 
 There are no constants of type x86_amx.
 
diff --git a/llvm/include/llvm/AsmParser/LLLexer.h b/llvm/include/llvm/AsmParser/LLLexer.h
index 501a7aefccd7f9..ae6c73b9ae75f5 100644
--- a/llvm/include/llvm/AsmParser/LLLexer.h
+++ b/llvm/include/llvm/AsmParser/LLLexer.h
@@ -112,6 +112,7 @@ namespace llvm {
     lltok::Kind Lex0x();
     lltok::Kind LexHash();
     lltok::Kind LexCaret();
+    lltok::Kind LexFloatStr();
 
     uint64_t atoull(const char *Buffer, const char *End);
     uint64_t HexIntToVal(const char *Buffer, const char *End);
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 7b47bc88ddb25f..2803313ce43fb1 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -497,10 +497,12 @@ enum Kind {
   DwarfMacinfo,     // DW_MACINFO_foo
   ChecksumKind,     // CSK_foo
   DbgRecordType,    // dbg_foo
+  FloatLiteral,     // Unparsed float literal
 
   // Type valued tokens (TyVal).
   Type,
 
+  FloatHexLiteral,  // f0x..., stored as APSInt
   APFloat, // APFloatVal
   APSInt   // APSInt
 };
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 5ea507c009bdc6..b5cbfd05c0fa6f 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -486,10 +486,11 @@ lltok::Kind LLLexer::LexHash() {
 }
 
 /// Lex a label, integer type, keyword, or hexadecimal integer constant.
-///    Label           [-a-zA-Z$._0-9]+:
-///    IntegerType     i[0-9]+
-///    Keyword         sdiv, float, ...
-///    HexIntConstant  [us]0x[0-9A-Fa-f]+
+///    Label            [-a-zA-Z$._0-9]+:
+///    IntegerType      i[0-9]+
+///    Keyword          sdiv, float, ...
+///    HexIntConstant   [us]0x[0-9A-Fa-f]+
+///    HexFloatConstant f0x[0-9A-Fa-f]+
 lltok::Kind LLLexer::LexIdentifier() {
   const char *StartChar = CurPtr;
   const char *IntEnd = CurPtr[-1] == 'i' ? nullptr : StartChar;
@@ -1021,11 +1022,13 @@ lltok::Kind LLLexer::LexIdentifier() {
   }
 
   // Check for [us]0x[0-9A-Fa-f]+ which are Hexadecimal constant generated by
-  // the CFE to avoid forcing it to deal with 64-bit numbers.
-  if ((TokStart[0] == 'u' || TokStart[0] == 's') &&
+  // the CFE to avoid forcing it to deal with 64-bit numbers. Also check for
+  // f0x[0-9A-Fa-f]+, which is the floating-point hexadecimal literal constant.
+  if ((TokStart[0] == 'u' || TokStart[0] == 's' || TokStart[0] == 'f') &&
       TokStart[1] == '0' && TokStart[2] == 'x' &&
       isxdigit(static_cast<unsigned char>(TokStart[3]))) {
-    int len = CurPtr-TokStart-3;
+    bool IsFloatConst = TokStart[0] == 'f';
+    int len = CurPtr - TokStart - 3;
     uint32_t bits = len * 4;
     StringRef HexStr(TokStart + 3, len);
     if (!all_of(HexStr, isxdigit)) {
@@ -1035,10 +1038,10 @@ lltok::Kind LLLexer::LexIdentifier() {
     }
     APInt Tmp(bits, HexStr, 16);
     uint32_t activeBits = Tmp.getActiveBits();
-    if (activeBits > 0 && activeBits < bits)
+    if (!IsFloatConst && activeBits > 0 && activeBits < bits)
       Tmp = Tmp.trunc(activeBits);
-    APSIntVal = APSInt(Tmp, TokStart[0] == 'u');
-    return lltok::APSInt;
+    APSIntVal = APSInt(Tmp, TokStart[0] != 's');
+    return IsFloatConst ? lltok::FloatHexLiteral : lltok::APSInt;
   }
 
   // If this is "cc1234", return this as just "cc".
@@ -1054,6 +1057,7 @@ lltok::Kind LLLexer::LexIdentifier() {
 
 /// Lex all tokens that start with a 0x prefix, knowing they match and are not
 /// labels.
+///    HexFPLiteral      [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
 ///    HexFPConstant     0x[0-9A-Fa-f]+
 ///    HexFP80Constant   0xK[0-9A-Fa-f]+
 ///    HexFP128Constant  0xL[0-9A-Fa-f]+
@@ -1080,6 +1084,11 @@ lltok::Kind LLLexer::Lex0x() {
   while (isxdigit(static_cast<unsigned char>(CurPtr[0])))
     ++CurPtr;
 
+  if (*CurPtr == '.') {
+    // HexFPLiteral, following C's %a syntax
+    return LexFloatStr();
+  }
+
   if (Kind == 'J') {
     // HexFPConstant - Floating point constant represented in IEEE format as a
     // hexadecimal number for when exponential notation is not precise enough.
@@ -1094,28 +1103,26 @@ lltok::Kind LLLexer::Lex0x() {
   default: llvm_unreachable("Unknown kind!");
   case 'K':
     // F80HexFPConstant - x87 long double in hexadecimal format (10 bytes)
-    FP80HexToIntPair(TokStart+3, CurPtr, Pair);
-    APFloatVal = APFloat(APFloat::x87DoubleExtended(), APInt(80, Pair));
-    return lltok::APFloat;
+    FP80HexToIntPair(TokStart + 3, CurPtr, Pair);
+    APSIntVal = APInt(80, Pair);
+    return lltok::FloatHexLiteral;
   case 'L':
     // F128HexFPConstant - IEEE 128-bit in hexadecimal format (16 bytes)
-    HexToIntPair(TokStart+3, CurPtr, Pair);
-    APFloatVal = APFloat(APFloat::IEEEquad(), APInt(128, Pair));
-    return lltok::APFloat;
+    HexToIntPair(TokStart + 3, CurPtr, Pair);
+    APSIntVal = APInt(128, Pair);
+    return lltok::FloatHexLiteral;
   case 'M':
     // PPC128HexFPConstant - PowerPC 128-bit in hexadecimal format (16 bytes)
-    HexToIntPair(TokStart+3, CurPtr, Pair);
-    APFloatVal = APFloat(APFloat::PPCDoubleDouble(), APInt(128, Pair));
-    return lltok::APFloat;
+    HexToIntPair(TokStart + 3, CurPtr, Pair);
+    APSIntVal = APInt(128, Pair);
+    return lltok::FloatHexLiteral;
   case 'H':
-    APFloatVal = APFloat(APFloat::IEEEhalf(),
-                         APInt(16,HexIntToVal(TokStart+3, CurPtr)));
-    return lltok::APFloat;
+    APSIntVal = APInt(16, HexIntToVal(TokStart + 3, CurPtr));
+    return lltok::FloatHexLiteral;
   case 'R':
     // Brain floating point
-    APFloatVal = APFloat(APFloat::BFloat(),
-                         APInt(16, HexIntToVal(TokStart + 3, CurPtr)));
-    return lltok::APFloat;
+    APSIntVal = APInt(16, HexIntToVal(TokStart + 3, CurPtr));
+    return lltok::FloatHexLiteral;
   }
 }
 
@@ -1124,6 +1131,7 @@ lltok::Kind LLLexer::Lex0x() {
 ///    NInteger          -[0-9]+
 ///    FPConstant        [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
 ///    PInteger          [0-9]+
+///    HexFPLiteral      [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
 ///    HexFPConstant     0x[0-9A-Fa-f]+
 ///    HexFP80Constant   0xK[0-9A-Fa-f]+
 ///    HexFP128Constant  0xL[0-9A-Fa-f]+
@@ -1139,7 +1147,9 @@ lltok::Kind LLLexer::LexDigitOrNegative() {
       return lltok::LabelStr;
     }
 
-    return lltok::Error;
+    // It might be a -inf, -nan, etc. Check if it's a float string (which will
+    // also handle error conditions there).
+    return LexFloatStr();
   }
 
   // At this point, it is either a label, int or fp constant.
@@ -1172,6 +1182,9 @@ lltok::Kind LLLexer::LexDigitOrNegative() {
   if (CurPtr[0] != '.') {
     if (TokStart[0] == '0' && TokStart[1] == 'x')
       return Lex0x();
+    if (TokStart[0] == '-' && TokStart[1] == '0' && TokStart[2] == 'x')
+      return LexFloatStr();
+
     APSIntVal = APSInt(StringRef(TokStart, CurPtr - TokStart));
     return lltok::APSInt;
   }
@@ -1190,26 +1203,31 @@ lltok::Kind LLLexer::LexDigitOrNegative() {
     }
   }
 
-  APFloatVal = APFloat(APFloat::IEEEdouble(),
-                       StringRef(TokStart, CurPtr - TokStart));
-  return lltok::APFloat;
+  StrVal.assign(TokStart, CurPtr - TokStart);
+  return lltok::FloatLiteral;
 }
 
 /// Lex a floating point constant starting with +.
-///    FPConstant  [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
+///    FPConstant   [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
+///    HexFPLiteral [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
+///    HexFPSpecial [-+](inf|qnan|nan\(0x[0-9A-Fa-f]+\))
 lltok::Kind LLLexer::LexPositive() {
-  // If the letter after the negative is a number, this is probably not a
-  // label.
+  // If it's not numeric, check for special floating-point values.
   if (!isdigit(static_cast<unsigned char>(CurPtr[0])))
-    return lltok::Error;
+    return LexFloatStr();
 
   // Skip digits.
   for (++CurPtr; isdigit(static_cast<unsigned char>(CurPtr[0])); ++CurPtr)
     /*empty*/;
 
+  // If the first non-digit is an x, check if it's a hex FP literal. LexFloatStr
+  // will reanalyze TokStr..CurPtr to make sure that it's 0x and not 413x.
+  if (CurPtr[0] == 'x')
+    return LexFloatStr();
+
   // At this point, we need a '.'.
   if (CurPtr[0] != '.') {
-    CurPtr = TokStart+1;
+    CurPtr = TokStart + 1;
     return lltok::Error;
   }
 
@@ -1227,7 +1245,111 @@ lltok::Kind LLLexer::LexPositive() {
     }
   }
 
-  APFloatVal = APFloat(APFloat::IEEEdouble(),
-                       StringRef(TokStart, CurPtr - TokStart));
-  return lltok::APFloat;
+  StrVal.assign(TokStart, CurPtr - TokStart);
+  return lltok::FloatLiteral;
+}
+
+/// Lex all tokens that start with a + or - that could be a float literal.
+///    HexFPLiteral      [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
+///    HexFPSpecial      [-+](inf|qnan|nan\(0x[0-9A-Fa-f]+\))
+lltok::Kind LLLexer::LexFloatStr() {
+  // At the point we enter this function, we may have seen a few characters
+  // already, but how many differs based on the entry point. Rewind to the
+  // beginning just in case.
+  CurPtr = TokStart;
+
+  // Check for optional sign.
+  if (*CurPtr == '-' || *CurPtr == '+')
+    ++CurPtr;
+
+  if (*CurPtr != '0') {
+    // Check for keywords.
+    const char *LabelStart = CurPtr;
+    while (isLabelChar(*CurPtr))
+      ++CurPtr;
+    StringRef Label(LabelStart, CurPtr - LabelStart);
+
+    // Basic special values.
+    if (Label == "inf") {
+      // Copy from the beginning, to include the sign.
+      StrVal.assign(TokStart, CurPtr - TokStart);
+      return lltok::FloatLiteral;
+    }
+
+    // APFloat::convertFromString doesn't support qnan, so translate it to a
+    // nan payload string it does support.
+    if (Label == "qnan") {
+      StrVal = *TokStart == '-' ? "-nan(0)" : "nan(0)";
+      return lltok::FloatLiteral;
+    }
+
+    // NaN with payload.
+    if (Label == "nan" && *CurPtr == '(') {
+      const char *Payload = ++CurPtr;
+      while (*CurPtr && *CurPtr != ')')
+        ++CurPtr;
+
+      // If no close parenthesis, it's a bad token, return it as an error.
+      if (*CurPtr++ != ')') {
+        CurPtr = TokStart + 1;
+        return lltok::Error;
+      }
+
+      StringRef PayloadStr(Payload, CurPtr - Payload);
+      APInt Val;
+      if (PayloadStr.consume_front("0x") && PayloadStr.getAsInteger(16, Val)) {
+        StrVal.assign(TokStart, CurPtr - TokStart);
+        // Drop the leading + from the string, as APFloat::convertFromString
+        // doesn't support leading + sign.
+        if (StrVal[0] == '+')
+          StrVal.erase(0, 1);
+        return lltok::FloatLiteral;
+      }
+    }
+
+    // Bad token, return it as an error.
+    CurPtr = TokStart + 1;
+    return lltok::Error;
+  }
+  ++CurPtr;
+
+  if (*CurPtr++ != 'x') {
+    // Bad token, return it as an error.
+    CurPtr = TokStart + 1;
+    return lltok::Error;
+  }
+
+  if (!isxdigit(static_cast<unsigned char>(CurPtr[0]))) {
+    // Bad token, return it as an error.
+    CurPtr = TokStart + 1;
+    return lltok::Error;
+  }
+
+  while (isxdigit(static_cast<unsigned char>(CurPtr[0])))
+    ++CurPtr;
+
+  if (*CurPtr != '.') {
+    // Bad token, return it as an error.
+    CurPtr = TokStart + 1;
+    return lltok::Error;
+  }
+
+  ++CurPtr; // Eat the .
+  while (isxdigit(static_cast<unsigned char>(CurPtr[0])))
+    ++CurPtr;
+
+  if (*CurPtr != 'p' && *CurPtr != 'P') {
+    // Bad token, return it as an error.
+    CurPtr = TokStart + 1;
+    return lltok::Error;
+  }
+
+  ++CurPtr;
+  if (*CurPtr == '+' || *CurPtr == '-')
+    ++CurPtr;
+  while (isdigit(static_cast<unsigned char>(CurPtr[0])))
+    ++CurPtr;
+
+  StrVal.assign(TokStart, CurPtr - TokStart);
+  return lltok::FloatLiteral;
 }
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 81d048b32e139b..23484870340eca 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3890,10 +3890,40 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
     ID.APSIntVal = Lex.getAPSIntVal();
     ID.Kind = ValID::t_APSInt;
     break;
-  case lltok::APFloat:
+  case lltok::APFloat: {
+    assert(ExpectedTy && "Need type to parse float values");
     ID.APFloatVal = Lex.getAPFloatVal();
     ID.Kind = ValID::t_APFloat;
     break;
+  }
+  case lltok::FloatLiteral: {
+    assert(ExpectedTy && "Need type to parse float values");
+    if (!ExpectedTy->isFloatingPointTy())
+      return error(ID.Loc, "floating point constant invalid for type");
+    ID.APFloatVal = APFloat(ExpectedTy->getFltSemantics());
+    auto Except = ID.APFloatVal.convertFromString(
+        Lex.getStrVal(), RoundingMode::NearestTiesToEven);
+    assert(Except && "Invalid float strings should be caught by the lexer");
+    // Forbid overflowing and underflowing literals, but permit inexact
+    // literals. Underflow is thrown when the result is denormal, so to allow
+    // denormals, only reject underflowing literals that resulted in a zero.
+    if (*Except & APFloat::opOverflow)
+      return error(ID.Loc, "floating point constant overflowed type");
+    if ((*Except & APFloat::opUnderflow) && ID.APFloatVal.isZero())
+      return error(ID.Loc, "floating point constant underflowed type");
+    ID.Kind = ValID::t_APFloat;
+    break;
+  }
+  case lltok::FloatHexLiteral: {
+    assert(ExpectedTy && "Need type to parse float values");
+    auto &Semantics = ExpectedTy->getFltSemantics();
+    const APInt &Bits = Lex.getAPSIntVal();
+    if (APFloat::getSizeInBits(Semantics) != Bits.getBitWidth())
+      return error(ID.Loc, "float hex literal has incorrect number of bits");
+    ID.APFloatVal = APFloat(Semantics, Bits);
+    ID.Kind = ValID::t_APFloat;
+    break;
+  }
   case lltok::kw_true:
     ID.ConstantVal = ConstantInt::getTrue(Context);
     ID.Kind = ValID::t_Constant;
@@ -6316,7 +6346,7 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
   C = nullptr;
   ValID ID;
   auto Loc = Lex.getLoc();
-  if (parseValID(ID, /*PFS=*/nullptr))
+  if (parseValID(ID, /*PFS=*/nullptr, /*ExpectedTy=*/Ty))
     return true;
   switch (ID.Kind) {
   case ValID::t_APSInt:
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 7153902fe2e7a6..c454fbe865c408 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -594,6 +594,22 @@ static Cursor maybeLexHexadecimalLiteral(Cursor C, MIToken &Token) {
   return C;
 }
 
+static Cursor maybeLexFloatHexBits(Cursor C, MIToken &Token) {
+  if (C.peek() != 'f')
+    return std::nullopt;
+  if (C.peek(1) != '0' || (C.peek(2) != 'x' && C.peek(2) != 'X'))
+    return std::nullopt;
+  Cursor Range = C;
+  C.advance(3);
+  while (isxdigit(C.peek()))
+    C.advance();
+  StringRef StrVal = Range.upto(C);
+  if (StrVal.size() <= 3)
+    return std::nullopt;
+  Token.reset(MIToken::FloatingPointLiteral, Range.upto(C));
+  return C;
+}
+
 static Cursor maybeLexNumericalLiteral(Cursor C, MIToken &Token) {
   if (!isdigit(C.peek()) && (C.peek() != '-' || !isdigit(C.peek(1))))
     return std::nullopt;
@@ -730,6 +746,8 @@ StringRef llvm::lexMIToken(StringRef Source, MIToken &Token,
 
   if (Cursor R = maybeLexMachineBasicBlock(C, Token, ErrorCallback))
     return R.remaining();
+  if (Cursor R = maybeLexFloatHexBits(C, Token))
+    return R.remaining();
   if (Cursor R = maybeLexIdentifier(C, Token))
     return R.remaining();
   if (Cursor R = maybeLexJumpTableIndex(C, Token))
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index b0d92ae37fe8f6..56a169dda1a8d9 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -3219,7 +3219,7 @@ bool IEEEFloat::convertFromStringSpecials(StringRef str) {
   if (str.size() < MIN_NAME_SIZE)
     return false;
 
-  if (str == "inf" || str == "INFINITY" || str == "+Inf") {
+  if (str == "inf" || str == "INFINITY" || str == "+Inf" || str == "+inf") {
     makeInf(false);
     return true;
   }
diff --git a/llvm/test/Assembler/float-literals.ll b/llvm/test/Assembler/float-literals.ll
new file mode 100644
index 00000000000000..f2f2f6ea7d688b
--- /dev/null
+++ b/llvm/test/Assembler/float-literals.ll
@@ -0,0 +1,40 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+; CHECK: @a = global float -0.000000e+00
+ at a = global float -0.0
+; CHECK: @b = global float 0.000000e+00
+ at b = global float +0.0
+; CHECK: @c = global float 0.000000e+00
+ at c = global float 0.0
+; CHECK: @d = global float 0.000000e+00
+ at d = global float 0.e1
+; CHECK: @e = global float 0.000000e+00
+ at e = global float 0.e-1
+; CHECK: @f = global float 0.000000e+00
+ at f = global float 0.e+1
+; CHECK: @g = global float 0x3DF0000000000000
+ at g = global float 0x1.0p-32
+; CHECK: @h = global float 0x41F0000000000000
+ at h = global float 0x1.0p+32
+; CHECK: @i = global float 0x41FC300000000000
+ at i = global float 0x1.c3p32
+; CHECK: @j = global float 0x3FFFF00000000000
+ at j = global float 0x1.ffp0
+; CHECK: @k = global float 0xC0FFFFFFE0000000
+ at k = global float -0xfff.fffp5
+; CHECK: @l = global float 0x4080FDE000000000
+ at l = global float +0x10.fdep5
+
+; CHECK: @0 = global double 0x7FF0000000000000
+ at 0 = global double +inf
+; CHECK: @1 = global ppc_fp128 f0x0000000000000000FFF0000000000000
+ at 1 = global ppc_fp128 -inf
+; CHECK: @2 = global half f0xFE00
+ at 2 = global half -qnan
+; CHECK: @3 = global bfloat f0x7FC0
+ at 3 = global bfloat +qnan
+; CHECK: @4 = global fp128 f0x7FFF80000000000000000000DEADBEEF
+ at 4 = global fp128 +nan(0xdeadbeef)
+; CHECK: @5 = global x86_fp80 f0x0001FFFF000000000000
+ at 5 = global x86_fp80 f0x0000ffff000000000000
+
diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index ce226705068afb..e2f254dd940def 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -82,6 +82,44 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
   ASSERT_TRUE(isa<ConstantFP>(V));
   EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(3.5));
 
+  V = parseConstantValue("double 0x13.5p-52", Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isDoubleTy());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(0x13.5p-52));
+
+  V = parseConstantValue("fp128 1.0e-4932", Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isFP128Ty());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->getValue().isDenormal());
+
+  V = parseConstantValue("fp128 1.1897314953572317650857593266280070162e4932",
+                         Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isFP128Ty());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(
+      APFloat::getLargest(APFloat::IEEEquad())));
+
+  V = parseConstantValue("float f0xabcdef01", Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isFloatTy());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(-0x1.9bde02p-40));
+
+  V = parseConstantValue("fp128 f0x80000000000000000000000000000000", Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isFP128Ty());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(-0.0));
+
+  V = parseConstantValue("fp128 -inf", Error, M);
+  ASSERT_TRUE(V);
+  EXPECT_TRUE(V->getType()->isFP128Ty());
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->getValue().isNegInfinity());
+
   V = parseConstantValue("i32 42", Error, M);
   ASSERT_TRUE(V);
   EXPECT_TRUE(V->getType()->isIntegerTy());
@@ -136,6 +174,15 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
 
   EXPECT_FALSE(parseConstantValue("i32 3, ", Error, M));
   EXPECT_EQ(Error.getMessage(), "expected end of string");
+
+  EXPECT_FALSE(parseConstantValue("double 1.0e999999999", Error, M));
+  EXPECT_EQ(Error.getMessage(), "floating point constant overflowed type");
+
+  EXPECT_FALSE(parseConstantValue("double 1.0e-999999999", Error, M));
+  EXPECT_EQ(Error.getMessage(), "floating point constant underflowed type");
+
+  EXPECT_FALSE(parseConstantValue("double 0x.25p-5", Error, M));
+  EXPECT_EQ(Error.getMessage(), "expected value token");
 }
 
 TEST(AsmParserTest, TypeAndConstantValueWithSlotMappingParsing) {

>From 3e76ef1488bbf8ef9124d63897ce7b052c872e5d Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Tue, 7 Jan 2025 08:11:57 -0800
Subject: [PATCH 2/6] Fix clang-format issues.

---
 llvm/include/llvm/AsmParser/LLToken.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 2803313ce43fb1..63d708515cf7c0 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -502,9 +502,9 @@ enum Kind {
   // Type valued tokens (TyVal).
   Type,
 
-  FloatHexLiteral,  // f0x..., stored as APSInt
-  APFloat, // APFloatVal
-  APSInt   // APSInt
+  FloatHexLiteral, // f0x..., stored as APSInt
+  APFloat,         // APFloatVal
+  APSInt           // APSInt
 };
 } // end namespace lltok
 } // end namespace llvm

>From 1e7908c0e7e4c0e2c359f8aeb00f383915c82f75 Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Tue, 7 Jan 2025 12:49:52 -0800
Subject: [PATCH 3/6] Address review comments.

---
 llvm/lib/AsmParser/LLLexer.cpp  | 16 ++++++++--------
 llvm/lib/AsmParser/LLParser.cpp |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index b5cbfd05c0fa6f..0199a8c25fef1b 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -1028,18 +1028,18 @@ lltok::Kind LLLexer::LexIdentifier() {
       TokStart[1] == '0' && TokStart[2] == 'x' &&
       isxdigit(static_cast<unsigned char>(TokStart[3]))) {
     bool IsFloatConst = TokStart[0] == 'f';
-    int len = CurPtr - TokStart - 3;
-    uint32_t bits = len * 4;
-    StringRef HexStr(TokStart + 3, len);
+    size_t Len = CurPtr - TokStart - 3;
+    uint32_t Bits = Len * 4;
+    StringRef HexStr(TokStart + 3, Len);
     if (!all_of(HexStr, isxdigit)) {
       // Bad token, return it as an error.
-      CurPtr = TokStart+3;
+      CurPtr = TokStart + 3;
       return lltok::Error;
     }
-    APInt Tmp(bits, HexStr, 16);
-    uint32_t activeBits = Tmp.getActiveBits();
-    if (!IsFloatConst && activeBits > 0 && activeBits < bits)
-      Tmp = Tmp.trunc(activeBits);
+    APInt Tmp(Bits, HexStr, 16);
+    uint32_t ActiveBits = Tmp.getActiveBits();
+    if (!IsFloatConst && ActiveBits > 0 && ActiveBits < Bits)
+      Tmp = Tmp.trunc(ActiveBits);
     APSIntVal = APSInt(Tmp, TokStart[0] != 's');
     return IsFloatConst ? lltok::FloatHexLiteral : lltok::APSInt;
   }
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 23484870340eca..7639cd959ae90c 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3916,7 +3916,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
   }
   case lltok::FloatHexLiteral: {
     assert(ExpectedTy && "Need type to parse float values");
-    auto &Semantics = ExpectedTy->getFltSemantics();
+    const auto &Semantics = ExpectedTy->getFltSemantics();
     const APInt &Bits = Lex.getAPSIntVal();
     if (APFloat::getSizeInBits(Semantics) != Bits.getBitWidth())
       return error(ID.Loc, "float hex literal has incorrect number of bits");

>From d0332f36a9d37c35b7723f0b0ef47eaa7964697e Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Tue, 7 Jan 2025 13:08:13 -0800
Subject: [PATCH 4/6] Fix remaining test failures after ripping out the
 asmwriter stuff.

---
 llvm/test/Assembler/float-literals.ll                  | 10 +++++-----
 .../MIR/NVPTX/floating-point-invalid-type-error.mir    |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/test/Assembler/float-literals.ll b/llvm/test/Assembler/float-literals.ll
index f2f2f6ea7d688b..c58fbd33669691 100644
--- a/llvm/test/Assembler/float-literals.ll
+++ b/llvm/test/Assembler/float-literals.ll
@@ -27,14 +27,14 @@
 
 ; CHECK: @0 = global double 0x7FF0000000000000
 @0 = global double +inf
-; CHECK: @1 = global ppc_fp128 f0x0000000000000000FFF0000000000000
+; CHECK: @1 = global ppc_fp128 0xMFFF00000000000000000000000000000
 @1 = global ppc_fp128 -inf
-; CHECK: @2 = global half f0xFE00
+; CHECK: @2 = global half 0xHFE00
 @2 = global half -qnan
-; CHECK: @3 = global bfloat f0x7FC0
+; CHECK: @3 = global bfloat 0xR7FC0
 @3 = global bfloat +qnan
-; CHECK: @4 = global fp128 f0x7FFF80000000000000000000DEADBEEF
+; CHECK: @4 = global fp128 0xL00000000DEADBEEF7FFF800000000000
 @4 = global fp128 +nan(0xdeadbeef)
-; CHECK: @5 = global x86_fp80 f0x0001FFFF000000000000
+; CHECK: @5 = global x86_fp80 0xK0001FFFF000000000000
 @5 = global x86_fp80 f0x0000ffff000000000000
 
diff --git a/llvm/test/CodeGen/MIR/NVPTX/floating-point-invalid-type-error.mir b/llvm/test/CodeGen/MIR/NVPTX/floating-point-invalid-type-error.mir
index 6280d4e90ebf1e..7ec0c80e8e6115 100644
--- a/llvm/test/CodeGen/MIR/NVPTX/floating-point-invalid-type-error.mir
+++ b/llvm/test/CodeGen/MIR/NVPTX/floating-point-invalid-type-error.mir
@@ -17,7 +17,7 @@ registers:
 body: |
   bb.0.entry:
     %0 = LD_f32_avar 0, 4, 1, 2, 32, &test_param_0
-  ; CHECK: [[@LINE+1]]:33: floating point constant does not have type 'float'
+  ; CHECK: [[@LINE+1]]:33: float hex literal has incorrect number of bits
     %1 = FADD_rnf32ri %0, float 0xH3C00
     StoreRetvalF32 %1, 0
     Return

>From e070228fcdbe28c314be19c6289c42cfceabafea Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Tue, 14 Jan 2025 11:36:02 -0800
Subject: [PATCH 5/6] Let snan constants actually be properly declared.

---
 llvm/docs/LangRef.rst                      | 60 ++++++++++++----------
 llvm/include/llvm/ADT/APFloat.h            | 19 +++++++
 llvm/lib/AsmParser/LLLexer.cpp             |  6 +--
 llvm/test/Assembler/float-literals.ll      |  6 ++-
 llvm/unittests/AsmParser/AsmParserTest.cpp |  7 +++
 5 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 2f874d1eecaffb..3fc7e9f3068358 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4612,34 +4612,38 @@ Simple Constants
 
 Floating-point constants support the following kinds of strings:
 
-   +---------------+---------------------------------------------------+
-   | Syntax        | Description                                       |
-   +===============+===================================================+
-   | ``+4.5e-13``  | Common decimal literal. Signs are optional, as is |
-   |               | the exponent portion. The decimal point is        |
-   |               | required, as is one or more leading digits before |
-   |               | the decimal point.                                |
-   +---------------+---------------------------------------------------+
-   | ``-0x1.fp13`` | Common hexadecimal literal. Signs are optional.   |
-   |               | The decimal point is required, as is the exponent |
-   |               | portion of the literal (after the ``p``).         |
-   +---------------+---------------------------------------------------+
-   | ``+inf``,     | Positive or negative infinity. The sign is        |
-   | ``-inf``      | required.                                         |
-   +---------------+---------------------------------------------------+
-   | ``+qnan``,    | Positive or negative preferred quiet NaN, i.e.,   |
-   | ``-qnan``     | the quiet bit is set, and all other payload bits  |
-   |               | are 0. The sign is required.                      |
-   +---------------+---------------------------------------------------+
-   | ``+nan(0x1)`` | NaN value with a particular payload, specified as |
-   |               | hexadecimal (including the quiet bit as part of   |
-   |               | the payload). The sign is required.               |
-   +---------------+---------------------------------------------------+
-   | ``f0x3c00``   | Value of the floating-point number if bitcast to  |
-   |               | an integer. The number must have exactly as many  |
-   |               | hexadecimal digits as is necessary for the size   |
-   |               | of the floating-point number.                     |
-   +---------------+---------------------------------------------------+
+   +----------------+---------------------------------------------------+
+   | Syntax         | Description                                       |
+   +================+===================================================+
+   | ``+4.5e-13``   | Common decimal literal. Signs are optional, as is |
+   |                | the exponent portion. The decimal point is        |
+   |                | required, as is one or more leading digits before |
+   |                | the decimal point.                                |
+   +----------------+---------------------------------------------------+
+   | ``-0x1.fp13``  | Common hexadecimal literal. Signs are optional.   |
+   |                | The decimal point is required, as is the exponent |
+   |                | portion of the literal (after the ``p``).         |
+   +----------------+---------------------------------------------------+
+   | ``+inf``,      | Positive or negative infinity. The sign is        |
+   | ``-inf``       | required.                                         |
+   +----------------+---------------------------------------------------+
+   | ``+qnan``,     | Positive or negative preferred quiet NaN, i.e.,   |
+   | ``-qnan``      | the quiet bit is set, and all other payload bits  |
+   |                | are 0. The sign is required.                      |
+   +----------------+---------------------------------------------------+
+   | ``+nan(0x1)``  | qNaN value with a particular payload, specified   |
+   |                | as hexadecimal (not including the quiet bit as    |
+   |                | part of the payload). The sign is required.       |
+   +----------------+---------------------------------------------------+
+   | ``+snan(0x1)`` | sNaN value with a particular payload, specified   |
+   |                | as hexadecimal (not including the quiet bit as    |
+   |                | part of the payload). The sign is required.       |
+   +----------------+---------------------------------------------------+
+   | ``f0x3c00``    | Value of the floating-point number if bitcast to  |
+   |                | an integer. The number must have exactly as many  |
+   |                | hexadecimal digits as is necessary for the size   |
+   |                | of the floating-point number.                     |
+   +----------------+---------------------------------------------------+
 
 There are no constants of type x86_amx.
 
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 9792749230cbf9..5685188162c3fd 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1347,6 +1347,25 @@ class APFloat : public APFloatBase {
     APFLOAT_DISPATCH_ON_SEMANTICS(
         convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM));
   }
+
+  /// Fill this APFloat with the result of a string conversion.
+  ///
+  /// The following strings are accepted for conversion purposes:
+  /// * Decimal floating-point literals (e.g., `0.1e-5`)
+  /// * Hexadecimal floating-point literals (e.g., `0x1.0p-5`)
+  /// * Positive infinity via "inf", "INFINITY", "Inf", "+Inf", or "+inf".
+  /// * Negative infinity via "-inf", "-INFINITY", or "-Inf".
+  /// * Quiet NaNs via "nan", "NaN", "nan(...)", or "NaN(...)", where the
+  ///   "..." is either a decimal or hexadecimal integer representing the
+  ///   payload. A negative sign may be optionally provided.
+  /// * Signaling NaNs via "snan", "sNaN", "snan(...)", or "sNaN(...)", where
+  ///   the "..." is either a decimal or hexadecimal integer representing the
+  ///   payload. A negative sign may be optionally provided.
+  ///
+  /// If the input string is none of these forms, then an error is returned.
+  ///
+  /// If a floating-point exception occurs during conversion, then no error is
+  /// returned, and the exception is indicated via opStatus.
   Expected<opStatus> convertFromString(StringRef, roundingMode);
   APInt bitcastToAPInt() const {
     APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt());
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 0199a8c25fef1b..7f4f710d0a323b 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -1210,7 +1210,7 @@ lltok::Kind LLLexer::LexDigitOrNegative() {
 /// Lex a floating point constant starting with +.
 ///    FPConstant   [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?
 ///    HexFPLiteral [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
-///    HexFPSpecial [-+](inf|qnan|nan\(0x[0-9A-Fa-f]+\))
+///    HexFPSpecial [-+](inf|qnan|s?nan\(0x[0-9A-Fa-f]+\))
 lltok::Kind LLLexer::LexPositive() {
   // If it's not numeric, check for special floating-point values.
   if (!isdigit(static_cast<unsigned char>(CurPtr[0])))
@@ -1251,7 +1251,7 @@ lltok::Kind LLLexer::LexPositive() {
 
 /// Lex all tokens that start with a + or - that could be a float literal.
 ///    HexFPLiteral      [-+]?0x[0-9A-Fa-f]+.[0-9A-Fa-f]*[pP][-+]?[0-9]+
-///    HexFPSpecial      [-+](inf|qnan|nan\(0x[0-9A-Fa-f]+\))
+///    HexFPSpecial      [-+](inf|qnan|s?nan\(0x[0-9A-Fa-f]+\))
 lltok::Kind LLLexer::LexFloatStr() {
   // At the point we enter this function, we may have seen a few characters
   // already, but how many differs based on the entry point. Rewind to the
@@ -1284,7 +1284,7 @@ lltok::Kind LLLexer::LexFloatStr() {
     }
 
     // NaN with payload.
-    if (Label == "nan" && *CurPtr == '(') {
+    if ((Label == "nan" || Label == "snan") && *CurPtr == '(') {
       const char *Payload = ++CurPtr;
       while (*CurPtr && *CurPtr != ')')
         ++CurPtr;
diff --git a/llvm/test/Assembler/float-literals.ll b/llvm/test/Assembler/float-literals.ll
index c58fbd33669691..fd29e9fef087ef 100644
--- a/llvm/test/Assembler/float-literals.ll
+++ b/llvm/test/Assembler/float-literals.ll
@@ -35,6 +35,8 @@
 @3 = global bfloat +qnan
 ; CHECK: @4 = global fp128 0xL00000000DEADBEEF7FFF800000000000
 @4 = global fp128 +nan(0xdeadbeef)
-; CHECK: @5 = global x86_fp80 0xK0001FFFF000000000000
- at 5 = global x86_fp80 f0x0000ffff000000000000
+; CHECK: @5 = global float 0x7FF000002000000
+ at 5 = global float +snan(0x1)
+; CHECK: @6 = global x86_fp80 0xK0001FFFF000000000000
+ at 6 = global x86_fp80 f0x0000ffff000000000000
 
diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index e2f254dd940def..a8d95d66de02be 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -120,6 +120,13 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
   ASSERT_TRUE(isa<ConstantFP>(V));
   EXPECT_TRUE(cast<ConstantFP>(V)->getValue().isNegInfinity());
 
+  const fltSemantics &Float = APFloatBase::IEEEsingle();
+  V = parseConstantValue("float +nan(0x1)", Error, M);
+  ASSERT_TRUE(V);
+  ASSERT_TRUE(isa<ConstantFP>(V));
+  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(APFloat::getNaN(Float, false, 1)));
+  EXPECT_TRUE(!cast<ConstantFP>(V)->getValue().isSignaling());
+
   V = parseConstantValue("i32 42", Error, M);
   ASSERT_TRUE(V);
   EXPECT_TRUE(V->getType()->isIntegerTy());

>From 44be9d14d28f268b85e8271df0395108a76c9f88 Mon Sep 17 00:00:00 2001
From: Joshua Cranmer <joshua.cranmer at intel.com>
Date: Tue, 14 Jan 2025 13:47:56 -0800
Subject: [PATCH 6/6] clang-format

---
 llvm/unittests/AsmParser/AsmParserTest.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index a8d95d66de02be..134889126a8430 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -124,7 +124,8 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
   V = parseConstantValue("float +nan(0x1)", Error, M);
   ASSERT_TRUE(V);
   ASSERT_TRUE(isa<ConstantFP>(V));
-  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(APFloat::getNaN(Float, false, 1)));
+  EXPECT_TRUE(
+      cast<ConstantFP>(V)->isExactlyValue(APFloat::getNaN(Float, false, 1)));
   EXPECT_TRUE(!cast<ConstantFP>(V)->getValue().isSignaling());
 
   V = parseConstantValue("i32 42", Error, M);



More information about the llvm-commits mailing list