[llvm] [LLParser] Support identifiers like `qnan` and `pinf` for special FP values (PR #102790)
Min-Yih Hsu via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 10 22:22:27 PDT 2024
https://github.com/mshockwave created https://github.com/llvm/llvm-project/pull/102790
Users can now write `qnan`, `snan`, `pinf`, and `ninf` for certain special floating point constants, instead of their hexadecimal values.
>From 56afe104594d4a206eb1334b0af8e5d1b8345775 Mon Sep 17 00:00:00 2001
From: Min Hsu <min at myhsu.dev>
Date: Sat, 10 Aug 2024 21:58:37 -0700
Subject: [PATCH] [LLParser] Support identifiers like `qnan` and `pinf` for FP
constants
Users can now write `qnan`, `snan`, `pinf`, and `ninf` for certain
special floating point constants, instead of the hexidecimal values.
---
llvm/docs/LangRef.rst | 36 +++++++++++++------
llvm/lib/AsmParser/LLParser.cpp | 15 ++++++++
llvm/unittests/AsmParser/AsmParserTest.cpp | 40 ++++++++++++++++++++++
3 files changed, 80 insertions(+), 11 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 0ee4d7b444cfcf..899474d2cc413b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4387,12 +4387,12 @@ 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
- :ref:`floating-point <t_floating>` type.
+ 123.421), exponential notation (e.g. 1.23421e+2), identifiers for special
+ values like ``qnan``, 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 :ref:`floating-point <t_floating>` type.
**Null pointer constants**
The identifier '``null``' is recognized as a null pointer constant
and must be of :ref:`pointer type <t_pointer>`.
@@ -4403,13 +4403,12 @@ Simple Constants
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
+than) '``double 4.5e+15``'. Hexadecimal floating-point
+constants are used 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.
+values are represented in their IEEE hexadecimal format. This ensures 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
@@ -4426,6 +4425,21 @@ 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).
+Some of the special floating point values can be represented by the following
+identifiers:
+
+ +-----------+---------------------------------------------------+
+ | Name | Description |
+ +===========+===================================================+
+ | ``qnan`` | Positive quiet NaN w/ payload equals to zero |
+ +-----------+---------------------------------------------------+
+ | ``snan`` | Positive signaling NaN w/ payload equals to zero |
+ +-----------+---------------------------------------------------+
+ | ``pinf`` | Positive infinity |
+ +-----------+---------------------------------------------------+
+ | ``ninf`` | Negative infinity |
+ +-----------+---------------------------------------------------+
+
There are no constants of type x86_amx.
.. _complexconstants:
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index f41907f0351257..fe909415eeab5b 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3833,6 +3833,21 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
case lltok::kw_poison: ID.Kind = ValID::t_Poison; break;
case lltok::kw_zeroinitializer: ID.Kind = ValID::t_Zero; break;
case lltok::kw_none: ID.Kind = ValID::t_None; break;
+ case lltok::kw_qnan:
+ ID.APFloatVal = APFloat::getQNaN(APFloat::IEEEdouble());
+ ID.Kind = ValID::t_APFloat;
+ break;
+ case lltok::kw_snan:
+ ID.APFloatVal = APFloat::getSNaN(APFloat::IEEEdouble());
+ ID.Kind = ValID::t_APFloat;
+ break;
+ case lltok::kw_pinf:
+ case lltok::kw_ninf:
+ ID.APFloatVal =
+ APFloat::getInf(APFloat::IEEEdouble(),
+ /*Negative=*/Lex.getKind() == lltok::kw_ninf);
+ ID.Kind = ValID::t_APFloat;
+ break;
case lltok::lbrace: {
// ValID ::= '{' ConstVector '}'
diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index a70c061d3e3044..7e1b000f17f922 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -82,6 +82,46 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) {
ASSERT_TRUE(isa<ConstantFP>(V));
EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(3.5));
+ // Special floating point constants.
+ const APFloat *APFloatVal;
+ V = parseConstantValue("double qnan", Error, M);
+ ASSERT_TRUE(V);
+ EXPECT_TRUE(V->getType()->isDoubleTy());
+ ASSERT_TRUE(isa<ConstantFP>(V));
+ APFloatVal = &cast<ConstantFP>(V)->getValueAPF();
+ EXPECT_TRUE(APFloatVal->isNaN() && !APFloatVal->isSignaling());
+
+ V = parseConstantValue("double snan", Error, M);
+ ASSERT_TRUE(V);
+ EXPECT_TRUE(V->getType()->isDoubleTy());
+ ASSERT_TRUE(isa<ConstantFP>(V));
+ APFloatVal = &cast<ConstantFP>(V)->getValueAPF();
+ EXPECT_TRUE(APFloatVal->isNaN() && APFloatVal->isSignaling());
+
+ V = parseConstantValue("double pinf", Error, M);
+ ASSERT_TRUE(V);
+ EXPECT_TRUE(V->getType()->isDoubleTy());
+ ASSERT_TRUE(isa<ConstantFP>(V));
+ APFloatVal = &cast<ConstantFP>(V)->getValueAPF();
+ EXPECT_TRUE(APFloatVal->isInfinity() && !APFloatVal->isNegative());
+
+ V = parseConstantValue("double ninf", Error, M);
+ ASSERT_TRUE(V);
+ EXPECT_TRUE(V->getType()->isDoubleTy());
+ ASSERT_TRUE(isa<ConstantFP>(V));
+ APFloatVal = &cast<ConstantFP>(V)->getValueAPF();
+ EXPECT_TRUE(APFloatVal->isInfinity() && APFloatVal->isNegative());
+
+ // We always parse special values into IEEEdouble first before converting
+ // them into the right semantics once the type info is available.
+ // The following tests whether this conversion works as expected.
+ V = parseConstantValue("bfloat pinf", Error, M);
+ ASSERT_TRUE(V);
+ EXPECT_TRUE(V->getType()->isBFloatTy());
+ ASSERT_TRUE(isa<ConstantFP>(V));
+ APFloatVal = &cast<ConstantFP>(V)->getValueAPF();
+ EXPECT_TRUE(APFloatVal->isInfinity() && !APFloatVal->isNegative());
+
V = parseConstantValue("i32 42", Error, M);
ASSERT_TRUE(V);
EXPECT_TRUE(V->getType()->isIntegerTy());
More information about the llvm-commits
mailing list