[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:28:28 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/5] [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/5] 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/5] 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/5] 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/5] 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());
More information about the llvm-commits
mailing list