[AsmParser] Revamp how floating-point literals work in LLVM IR. (#190641)
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. The current hexadecimal syntax is retained for the moment, but it is expected to be ripped out after the next release of LLVM. These changes were discussed in an RFC at https://discourse.llvm.org/t/rfc-floating-point-literals-in-llvm-ir/82974.
This commit is contained in:
@@ -4953,11 +4953,13 @@ Simple Constants
|
||||
``store b8 42, ptr %p`` is equivalent to ``store i8 42, ptr %p``.
|
||||
**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
|
||||
@@ -4966,31 +4968,53 @@ 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.
|
||||
Floating-point constants support the following kinds of strings:
|
||||
|
||||
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
|
||||
IEEE 754 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).
|
||||
+----------------+---------------------------------------------------+
|
||||
| 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 is a legacy syntax for hexadecimal floating-point literals that will be
|
||||
removed in the future. In this format, constants are represented as their
|
||||
underlying integer representation as in the ``f0x3c00`` syntax, but instead
|
||||
use slightly different prefixes. ``float`` and ``double`` use ``0x`` followed
|
||||
by 16 hexadecimal digits representing the equivalent ``double`` value bitcast
|
||||
to an integer type. ``bfloat`` uses ``0xR`` followed by 4 hexadecimal digits.
|
||||
``half`` uses ``0xH`` followed by 4 hexadecimal digits. ``x86_fp80`` uses
|
||||
``0xK`` followed by 20 hexadecimal digits. ``ppc_fp128`` uses ``0xM``
|
||||
followed by 32 hexadecimal digits. ``fp128`` uses ``0xL`` followed by 32
|
||||
hexadecimal digits. For the last two types only, the bits are not fully
|
||||
written in big-endian order but rather with the low 64 bits written in
|
||||
big-endian then the high 64 bits written in big-endian.
|
||||
|
||||
There are no constants of type x86_amx.
|
||||
|
||||
|
||||
@@ -69,6 +69,15 @@ Changes to the LLVM IR
|
||||
* The `"nooutline"` attribute is now writen as `nooutline`. Existing IR and
|
||||
bitcode will be automatically updated.
|
||||
|
||||
* LLVM IR floating-point literals have greatly changed:
|
||||
|
||||
* The old hexadecimal bitwise representation is deprecated and will be removed
|
||||
in the next revision. It is replaced with a unified `f0x` prefix.
|
||||
|
||||
* Hexadecimal literals akin to C99's syntax are supported.
|
||||
|
||||
* Special values for infinities and NaNs, including NaN payloads, are added.
|
||||
|
||||
Changes to LLVM infrastructure
|
||||
------------------------------
|
||||
|
||||
|
||||
@@ -1404,7 +1404,25 @@ public:
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(convertFromAPInt(Input, IsSigned, RM));
|
||||
}
|
||||
|
||||
LLVM_ABI Expected<opStatus> convertFromString(StringRef, roundingMode);
|
||||
/// 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());
|
||||
}
|
||||
|
||||
@@ -126,6 +126,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);
|
||||
|
||||
@@ -523,12 +523,14 @@ enum Kind {
|
||||
ChecksumKind, // CSK_foo
|
||||
DbgRecordType, // dbg_foo
|
||||
DwarfEnumKind, // DW_APPLE_ENUM_KIND_foo
|
||||
FloatLiteral, // Unparsed float literal
|
||||
|
||||
// Type valued tokens (TyVal).
|
||||
Type,
|
||||
|
||||
APFloat, // APFloatVal
|
||||
APSInt // APSInt
|
||||
FloatHexLiteral, // f0x..., stored as APSInt
|
||||
APFloat, // APFloatVal
|
||||
APSInt // APSInt
|
||||
};
|
||||
} // end namespace lltok
|
||||
} // end namespace llvm
|
||||
|
||||
@@ -494,6 +494,7 @@ lltok::Kind LLLexer::LexHash() {
|
||||
/// 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 IntOrByteIdentifier = CurPtr[-1];
|
||||
@@ -1066,24 +1067,26 @@ 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;
|
||||
uint32_t bits = len * 4;
|
||||
StringRef HexStr(TokStart + 3, len);
|
||||
bool IsFloatConst = TokStart[0] == 'f';
|
||||
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 (activeBits > 0 && activeBits < bits)
|
||||
Tmp = Tmp.trunc(activeBits);
|
||||
APSIntVal = APSInt(Tmp, TokStart[0] == 'u');
|
||||
return lltok::APSInt;
|
||||
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;
|
||||
}
|
||||
|
||||
// If this is "cc1234", return this as just "cc".
|
||||
@@ -1099,6 +1102,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]+
|
||||
@@ -1125,6 +1129,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.
|
||||
@@ -1136,30 +1145,31 @@ lltok::Kind LLLexer::Lex0x() {
|
||||
|
||||
uint64_t Pair[2];
|
||||
switch (Kind) {
|
||||
default: llvm_unreachable("Unknown kind!");
|
||||
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': {
|
||||
uint64_t Val = HexIntToVal(TokStart + 3, CurPtr);
|
||||
if (!llvm::isUInt<16>(Val)) {
|
||||
LexError("hexadecimal constant too large for half (16-bit)");
|
||||
return lltok::Error;
|
||||
}
|
||||
APFloatVal = APFloat(APFloat::IEEEhalf(), APInt(16, Val));
|
||||
return lltok::APFloat;
|
||||
APSIntVal = APInt(16, Val);
|
||||
return lltok::FloatHexLiteral;
|
||||
}
|
||||
case 'R': {
|
||||
// Brain floating point
|
||||
@@ -1168,8 +1178,8 @@ lltok::Kind LLLexer::Lex0x() {
|
||||
LexError("hexadecimal constant too large for bfloat (16-bit)");
|
||||
return lltok::Error;
|
||||
}
|
||||
APFloatVal = APFloat(APFloat::BFloat(), APInt(16, Val));
|
||||
return lltok::APFloat;
|
||||
APSIntVal = APInt(16, Val);
|
||||
return lltok::FloatHexLiteral;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1179,6 +1189,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]+
|
||||
@@ -1194,7 +1205,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.
|
||||
@@ -1227,6 +1240,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;
|
||||
}
|
||||
@@ -1245,26 +1261,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|s?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;
|
||||
}
|
||||
|
||||
@@ -1282,7 +1303,113 @@ 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|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
|
||||
// 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" || Label == "snan") && *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;
|
||||
LexError("unclosed nan literal");
|
||||
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.
|
||||
LexError("bad payload format for nan literal");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -4148,10 +4148,41 @@ 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: {
|
||||
ID.APFloatVal = Lex.getAPFloatVal();
|
||||
ID.Kind = ValID::t_APFloat;
|
||||
break;
|
||||
}
|
||||
case lltok::FloatLiteral: {
|
||||
if (!ExpectedTy)
|
||||
return error(ID.Loc, "unexpected floating-point literal");
|
||||
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: {
|
||||
if (!ExpectedTy)
|
||||
return error(ID.Loc, "unexpected floating-point literal");
|
||||
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");
|
||||
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;
|
||||
@@ -6850,7 +6881,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:
|
||||
|
||||
@@ -599,6 +599,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;
|
||||
@@ -736,6 +752,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))
|
||||
|
||||
@@ -3053,7 +3053,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;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
; This tests that a simple error is caught and processed correctly.
|
||||
; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: floating point constant invalid for type
|
||||
; CHECK: floating-point constant invalid for type
|
||||
|
||||
define void @test() {
|
||||
add i32 1, 2.0
|
||||
|
||||
53
llvm/test/Assembler/float-literals.ll
Normal file
53
llvm/test/Assembler/float-literals.ll
Normal file
@@ -0,0 +1,53 @@
|
||||
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
|
||||
|
||||
; CHECK: @a = global float -0.000000e+00
|
||||
@a = global float -0.0
|
||||
; CHECK: @b = global float 0.000000e+00
|
||||
@b = global float +0.0
|
||||
; CHECK: @c = global float 0.000000e+00
|
||||
@c = global float 0.0
|
||||
; CHECK: @d = global float 0.000000e+00
|
||||
@d = global float 0.e1
|
||||
; CHECK: @e = global float 0.000000e+00
|
||||
@e = global float 0.e-1
|
||||
; CHECK: @f = global float 0.000000e+00
|
||||
@f = global float 0.e+1
|
||||
; CHECK: @g = global float 0x3DF0000000000000
|
||||
@g = global float 0x1.0p-32
|
||||
; CHECK: @h = global float 0x41F0000000000000
|
||||
@h = global float 0x1.0p+32
|
||||
; CHECK: @i = global float 0x41FC300000000000
|
||||
@i = global float 0x1.c3p32
|
||||
; CHECK: @j = global float 0x3FFFF00000000000
|
||||
@j = global float 0x1.ffp0
|
||||
; CHECK: @k = global float 0xC0FFFFFFE0000000
|
||||
@k = global float -0xfff.fffp5
|
||||
; CHECK: @l = global float 0x4080FDE000000000
|
||||
@l = global float +0x10.fdep5
|
||||
|
||||
; CHECK: @0 = global double 0x7FF0000000000000
|
||||
@0 = global double +inf
|
||||
; CHECK: @1 = global ppc_fp128 0xMFFF00000000000000000000000000000
|
||||
@1 = global ppc_fp128 -inf
|
||||
; CHECK: @2 = global half 0xHFE00
|
||||
@2 = global half -qnan
|
||||
; CHECK: @3 = global bfloat 0xR7FC0
|
||||
@3 = global bfloat +qnan
|
||||
; CHECK: @4 = global fp128 0xL00000000DEADBEEF7FFF800000000000
|
||||
@4 = global fp128 +nan(0xdeadbeef)
|
||||
; CHECK: @5 = global float 0x7FF000002000000
|
||||
@5 = global float +snan(0x1)
|
||||
; CHECK: @6 = global x86_fp80 0xK0001FFFF000000000000
|
||||
@6 = global x86_fp80 f0x0000ffff000000000000
|
||||
; CHECK: @7 = global float 0xB810000000000000
|
||||
@7 = global float -0x1.0p-126
|
||||
; CHECK: @8 = global double 0x7FEFFFFFFFFFFFFF
|
||||
@8 = global double 1.79769313486231570815e+308
|
||||
|
||||
; CHECK-COUNT-3: global half 0xH01E3
|
||||
@denormal.hex = global half +0x1.e3p-16
|
||||
@denormal.dec = global half 2.878904342651367875e-5
|
||||
@denormal.bits = global half f0x01e3
|
||||
|
||||
; CHECK: @legacy = global float 0x3FB99999A0000000
|
||||
@legacy = global float 0x3FB99999A0000000
|
||||
6
llvm/test/Assembler/invalid-call-float-literal.ll
Normal file
6
llvm/test/Assembler/invalid-call-float-literal.ll
Normal file
@@ -0,0 +1,6 @@
|
||||
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||
; CHECK: error: unexpected floating-point literal
|
||||
|
||||
define void @foo() {
|
||||
call void f0x12345678()
|
||||
}
|
||||
11
llvm/test/Assembler/invalid-uselistorder_bb-float-literal.ll
Normal file
11
llvm/test/Assembler/invalid-uselistorder_bb-float-literal.ll
Normal file
@@ -0,0 +1,11 @@
|
||||
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||
; CHECK: error: unexpected floating-point literal
|
||||
|
||||
@ba1 = constant ptr blockaddress (@foo, %1)
|
||||
|
||||
define void @foo() {
|
||||
br label %1
|
||||
unreachable
|
||||
}
|
||||
|
||||
uselistorder_bb 1.0, %1, { 1, 0 }
|
||||
@@ -17,7 +17,7 @@ registers:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
%0 = LD_i32 0, 4, 1, 2, 32, &test_param_0, 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
|
||||
StoreRetvalI32 %1, 0
|
||||
Return
|
||||
|
||||
@@ -88,6 +88,52 @@ 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)->getValue().isNegZero());
|
||||
|
||||
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());
|
||||
|
||||
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());
|
||||
@@ -135,13 +181,46 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
|
||||
EXPECT_EQ(Error.getMessage(), "expected type");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("i32 3.25", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "floating point constant invalid for type");
|
||||
EXPECT_EQ(Error.getMessage(), "floating-point constant invalid for type");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("ptr @foo", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "expected a constant value");
|
||||
|
||||
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");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("double f0x0", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(),
|
||||
"float hex literal has incorrect number of bits");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("double f0x0123456789abcdef0", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(),
|
||||
"float hex literal has incorrect number of bits");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("float 0x3FBCC2794DBD00E1", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "floating point constant invalid for type");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("x86_fp80 0x3FBCC2794DBD00E1", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(),
|
||||
"floating point constant does not have type 'x86_fp80'");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("float +nan(0x1", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "unclosed nan literal");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("float +nan(payload)", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "bad payload format for nan literal");
|
||||
|
||||
EXPECT_FALSE(parseConstantValue("float 0xz", Error, M));
|
||||
EXPECT_EQ(Error.getMessage(), "expected value token");
|
||||
}
|
||||
|
||||
TEST(AsmParserTest, TypeAndConstantValueWithSlotMappingParsing) {
|
||||
|
||||
Reference in New Issue
Block a user