diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 8cc9036d1b67f..3fc7e9f306835 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 ` type. **Null pointer constants** The identifier '``null``' is recognized as a null pointer constant @@ -4608,31 +4610,40 @@ Simple Constants The identifier '``none``' is recognized as an empty token constant and must be of :ref:`token type `. -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)`` | 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 9792749230cbf..5685188162c3f 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 convertFromString(StringRef, roundingMode); APInt bitcastToAPInt() const { APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt()); diff --git a/llvm/include/llvm/AsmParser/LLLexer.h b/llvm/include/llvm/AsmParser/LLLexer.h index 501a7aefccd7f..ae6c73b9ae75f 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 7b47bc88ddb25..63d708515cf7c 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -497,12 +497,14 @@ enum Kind { DwarfMacinfo, // DW_MACINFO_foo ChecksumKind, // CSK_foo DbgRecordType, // dbg_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 diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 5ea507c009bdc..7f4f710d0a323 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,24 +1022,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(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". @@ -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(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|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(CurPtr[0]))) - return lltok::Error; + return LexFloatStr(); // Skip digits. for (++CurPtr; isdigit(static_cast(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|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; + 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(CurPtr[0]))) { + // Bad token, return it as an error. + CurPtr = TokStart + 1; + return lltok::Error; + } + + while (isxdigit(static_cast(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(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(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 81d048b32e139..7639cd959ae90 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"); + 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; @@ -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 7153902fe2e7a..c454fbe865c40 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 b0d92ae37fe8f..56a169dda1a8d 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 0000000000000..fd29e9fef087e --- /dev/null +++ b/llvm/test/Assembler/float-literals.ll @@ -0,0 +1,42 @@ +; 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 + 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 6280d4e90ebf1..7ec0c80e8e611 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 diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp index ce226705068af..134889126a843 100644 --- a/llvm/unittests/AsmParser/AsmParserTest.cpp +++ b/llvm/unittests/AsmParser/AsmParserTest.cpp @@ -82,6 +82,52 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) { ASSERT_TRUE(isa(V)); EXPECT_TRUE(cast(V)->isExactlyValue(3.5)); + V = parseConstantValue("double 0x13.5p-52", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isDoubleTy()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->isExactlyValue(0x13.5p-52)); + + V = parseConstantValue("fp128 1.0e-4932", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isFP128Ty()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->getValue().isDenormal()); + + V = parseConstantValue("fp128 1.1897314953572317650857593266280070162e4932", + Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isFP128Ty()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->isExactlyValue( + APFloat::getLargest(APFloat::IEEEquad()))); + + V = parseConstantValue("float f0xabcdef01", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isFloatTy()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->isExactlyValue(-0x1.9bde02p-40)); + + V = parseConstantValue("fp128 f0x80000000000000000000000000000000", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isFP128Ty()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->isExactlyValue(-0.0)); + + V = parseConstantValue("fp128 -inf", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isFP128Ty()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->getValue().isNegInfinity()); + + const fltSemantics &Float = APFloatBase::IEEEsingle(); + V = parseConstantValue("float +nan(0x1)", Error, M); + ASSERT_TRUE(V); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE( + cast(V)->isExactlyValue(APFloat::getNaN(Float, false, 1))); + EXPECT_TRUE(!cast(V)->getValue().isSignaling()); + V = parseConstantValue("i32 42", Error, M); ASSERT_TRUE(V); EXPECT_TRUE(V->getType()->isIntegerTy()); @@ -136,6 +182,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) {