Skip to content

Commit 3492c06

Browse files
committed
Apply comments
Signed-off-by: Sidorov, Dmitry <[email protected]>
1 parent 37faca6 commit 3492c06

File tree

8 files changed

+355
-170
lines changed

8 files changed

+355
-170
lines changed

llvm/docs/LangRef.rst

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21407,7 +21407,7 @@ This intrinsic is not supported on all targets. Some targets may not support
2140721407
all rounding modes.
2140821408

2140921409
'``llvm.convert.to.arbitrary.fp``' Intrinsic
21410-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21410+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2141121411

2141221412
Syntax:
2141321413
"""""""
@@ -21446,20 +21446,53 @@ Arguments:
2144621446
accepted by :ref:`llvm.fptrunc.round <int_fptrunc_round>` (for example,
2144721447
``"round.tonearest"`` or ``"round.towardzero"``).
2144821448

21449+
The rounding mode is only consulted when ``value`` is not exactly representable in the target format.
21450+
If the value is exactly representable, all rounding modes produce the same result.
21451+
2144921452
``saturation``
21450-
A compile-time constant boolean value (``i1``). When ``true``, values outside the
21451-
representable range of the target format are clamped to the minimum or maximum normal value.
21452-
When ``false``, no saturation is applied. This parameter must be an immediate constant.
21453+
A compile-time constant boolean value (``i1``). This parameter controls how overflow is handled
21454+
when values exceed the representable finite range of the target format:
21455+
21456+
- When ``true``: overflowing values are clamped to the minimum or maximum representable finite value
21457+
(saturating to the largest negative finite value or largest positive finite value).
21458+
- When ``false``: overflowing values are converted to infinity (preserving sign of the original value) if the
21459+
target format supports infinity, or return a poison value if infinity is not supported
21460+
by the target format.
21461+
21462+
This parameter must be an immediate constant.
2145321463

2145421464
Semantics:
2145521465
""""""""""
2145621466

2145721467
The intrinsic converts the native LLVM floating-point value to the arbitrary FP
2145821468
format specified by ``interpretation``, applying the requested rounding mode and
21459-
saturation behavior. The result is returned as an integer (e.g., ``i8`` for FP8,
21460-
``i6`` for FP6) containing the encoded arbitrary FP bits. When saturation is enabled,
21461-
values that exceed the representable range are clamped to the minimum or maximum
21462-
normal value of the target format.
21469+
saturation behavior. The conversion is performed in two steps: first, the value is
21470+
rounded according to the specified rounding mode to fit the target format's precision;
21471+
then, if the rounded result exceeds the target format's representable range, saturation
21472+
is applied according to the ``saturation`` parameter. The result is returned as an
21473+
integer (e.g., ``i8`` for FP8, ``i6`` for FP6) containing the encoded arbitrary FP bits.
21474+
21475+
**Handling of special values:**
21476+
21477+
- **NaN**: If the input is NaN and the target format supports NaN, it is converted to a NaN
21478+
representation in the target format. The exact NaN payload and quiet/signaling status are
21479+
implementation-defined; implementations may preserve them when the target supports it.
21480+
If the target format does not support NaN, the intrinsic returns a poison value.
21481+
- **Infinity**: If the input is +/-Inf:
21482+
21483+
- When ``saturation`` is ``false`` and the target format supports infinity, +/-Inf is preserved.
21484+
- When ``saturation`` is ``false`` and the target format does not support infinity (e.g., formats
21485+
with "FN" suffix), the intrinsic returns a poison value.
21486+
- When ``saturation`` is ``true``, +/-Inf is clamped to the maximum/minimum representable finite value.
21487+
21488+
- **Overflow**: When a finite value exceeds the representable range:
21489+
21490+
- When ``saturation`` is ``true``, the value is clamped to the maximum/minimum representable finite value.
21491+
- When ``saturation`` is ``false`` and the target format supports infinity, the value becomes +/-Inf.
21492+
- When ``saturation`` is ``false`` and the target format does not support infinity, the intrinsic
21493+
returns a poison value.
21494+
21495+
For FP6/FP4 interpretations, producers are expected to use ``saturation`` = ``true``; using ``saturation`` = ``false`` and generating NaN/Inf/overflowing values is undefined (poison).
2146321496

2146421497
Example:
2146521498
""""""""
@@ -21477,16 +21510,15 @@ Example:
2147721510
metadata !"round.towardzero", i1 true)
2147821511

2147921512
'``llvm.convert.from.arbitrary.fp``' Intrinsic
21480-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21513+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2148121514

2148221515
Syntax:
2148321516
"""""""
2148421517

2148521518
::
2148621519

2148721520
declare <fNxM> @llvm.convert.from.arbitrary.fp.<fNxM>.<iNxM>(
21488-
<iNxM> <value>, metadata <interpretation>,
21489-
metadata <rounding mode>, i1 <saturation>)
21521+
<iNxM> <value>, metadata <interpretation>)
2149021522

2149121523
Overview:
2149221524
"""""""""
@@ -21510,24 +21542,20 @@ Arguments:
2151021542
- FP6 formats: ``"Float6E3M2FN"``, ``"Float6E2M3FN"``
2151121543
- FP4 formats: ``"Float4E2M1FN"``
2151221544

21513-
``rounding mode``
21514-
A metadata string specifying the rounding mode. The permitted strings match those
21515-
accepted by :ref:`llvm.fptrunc.round <int_fptrunc_round>` (for example,
21516-
``"round.tonearest"`` or ``"round.towardzero"``).
21517-
21518-
``saturation``
21519-
A compile-time constant boolean value (``i1``). When ``true``, values outside the
21520-
representable range of the target format are clamped to the minimum or maximum normal value.
21521-
When ``false``, no saturation is applied. This parameter must be an immediate constant.
21522-
2152321545
Semantics:
2152421546
""""""""""
2152521547

2152621548
The intrinsic interprets the integer value as arbitrary FP bits according to
21527-
``interpretation``, then converts to the native LLVM floating-point result type,
21528-
applying the requested rounding mode and saturation behavior. When saturation is
21529-
enabled, values that exceed the representable range of the target format are
21530-
clamped to the minimum or maximum normal value.
21549+
``interpretation``, then converts to the native LLVM floating-point result type.
21550+
21551+
Conversions from arbitrary FP formats to native LLVM floating-point types are typically
21552+
widening conversions (e.g., FP8 to FP16 or FP32), which are exact and require no rounding.
21553+
Normal finite values are converted exactly. NaN values in the source format are converted to
21554+
NaN in the target format. The exact NaN payload and quiet/signaling status are
21555+
implementation-defined; implementations may preserve them when the target supports it.
21556+
Infinity values are preserved as infinity. If a value exceeds the representable range of the
21557+
target type (for example, converting ``Float8E8M0FNU`` with large exponents to ``half``),
21558+
the result is converted to infinity with the appropriate sign.
2153121559

2153221560
Example:
2153321561
""""""""
@@ -21536,13 +21564,11 @@ Example:
2153621564

2153721565
; Convert FP8 E4M3 bits to half
2153821566
%half_val = call half @llvm.convert.from.arbitrary.fp.f16.i8(
21539-
i8 %fp8bits, metadata !"Float8E4M3",
21540-
metadata !"round.tonearest", i1 false)
21567+
i8 %fp8bits, metadata !"Float8E4M3")
2154121568

2154221569
; Convert vector of FP8 E5M2 bits to float
2154321570
%vec_float = call <4 x float> @llvm.convert.from.arbitrary.fp.v4f32.v4i8(
21544-
<4 x i8> %fp8_values, metadata !"Float8E5M2",
21545-
metadata !"round.tonearest", i1 false)
21571+
<4 x i8> %fp8_values, metadata !"Float8E5M2")
2154621572

2154721573
Convergence Intrinsics
2154821574
----------------------

llvm/include/llvm/IR/Intrinsics.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ namespace Intrinsic {
284284
/// N.
285285
LLVM_ABI Intrinsic::ID getDeinterleaveIntrinsicID(unsigned Factor);
286286

287+
/// Returns true if the given string is a valid arbitrary floating-point
288+
/// format interpretation for llvm.convert.to.arbitrary.fp and
289+
/// llvm.convert.from.arbitrary.fp intrinsics.
290+
LLVM_ABI bool isValidArbitraryFPFormat(StringRef Format);
291+
287292
} // namespace Intrinsic
288293

289294
} // namespace llvm

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,8 +1104,8 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
11041104
def int_convert_from_arbitrary_fp
11051105
: DefaultAttrsIntrinsic<
11061106
[ llvm_anyfloat_ty ],
1107-
[ llvm_anyint_ty, llvm_metadata_ty, llvm_metadata_ty, llvm_i1_ty ],
1108-
[ IntrNoMem, IntrSpeculatable, ImmArg<ArgIndex<3>> ]>;
1107+
[ llvm_anyint_ty, llvm_metadata_ty ],
1108+
[ IntrNoMem, IntrSpeculatable ]>;
11091109

11101110
def int_canonicalize : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>],
11111111
[IntrNoMem]>;

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2842,10 +2842,7 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
28422842
if (!MDN) {
28432843
if (auto *ConstMD = dyn_cast<ConstantAsMetadata>(MD))
28442844
MDN = MDNode::get(MF->getFunction().getContext(), ConstMD);
2845-
else if (auto *MDS = dyn_cast<MDString>(MD)) {
2846-
Metadata *Ops[] = {MDS};
2847-
MDN = MDNode::get(MF->getFunction().getContext(), Ops);
2848-
} else
2845+
else // This was probably an MDString.
28492846
return false;
28502847
}
28512848
MIB.addMetadata(MDN);

llvm/lib/IR/Intrinsics.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,3 +1142,12 @@ Intrinsic::ID Intrinsic::getDeinterleaveIntrinsicID(unsigned Factor) {
11421142
assert(Factor >= 2 && Factor <= 8 && "Unexpected factor");
11431143
return InterleaveIntrinsics[Factor - 2].Deinterleave;
11441144
}
1145+
1146+
bool Intrinsic::isValidArbitraryFPFormat(StringRef Format) {
1147+
return Format == "Float8E5M2" || Format == "Float8E5M2FNUZ" ||
1148+
Format == "Float8E4M3" || Format == "Float8E4M3FN" ||
1149+
Format == "Float8E4M3FNUZ" || Format == "Float8E4M3B11FNUZ" ||
1150+
Format == "Float8E3M4" || Format == "Float8E8M0FNU" ||
1151+
Format == "Float6E3M2FN" || Format == "Float6E2M3FN" ||
1152+
Format == "Float4E2M1FN";
1153+
}

llvm/lib/IR/Verifier.cpp

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5849,9 +5849,24 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
58495849
"unsupported rounding mode argument", Call);
58505850
break;
58515851
}
5852-
case Intrinsic::convert_to_arbitrary_fp:
5853-
case Intrinsic::convert_from_arbitrary_fp: {
5854-
// Check interpretation metadata (argoperand 1)
5852+
case Intrinsic::convert_to_arbitrary_fp: {
5853+
// Check that vector element counts are consistent.
5854+
Type *ValueTy = Call.getArgOperand(0)->getType();
5855+
Type *IntTy = Call.getType();
5856+
5857+
if (auto *ValueVecTy = dyn_cast<VectorType>(ValueTy)) {
5858+
auto *IntVecTy = dyn_cast<VectorType>(IntTy);
5859+
Check(IntVecTy,
5860+
"if floating-point operand is a vector, integer operand must also "
5861+
"be a vector",
5862+
Call);
5863+
Check(ValueVecTy->getElementCount() == IntVecTy->getElementCount(),
5864+
"floating-point and integer vector operands must have the same "
5865+
"element count",
5866+
Call);
5867+
}
5868+
5869+
// Check interpretation metadata (argoperand 1).
58555870
auto *InterpMAV = dyn_cast<MetadataAsValue>(Call.getArgOperand(1));
58565871
Check(InterpMAV, "missing interpretation metadata operand", Call);
58575872
auto *InterpStr = dyn_cast<MDString>(InterpMAV->getMetadata());
@@ -5861,16 +5876,11 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
58615876
Check(!Interp.empty(), "interpretation metadata string must not be empty",
58625877
Call);
58635878

5864-
// Valid interpretation strings: mini-float format names
5865-
bool IsKnown = Interp == "Float8E5M2" || Interp == "Float8E5M2FNUZ" ||
5866-
Interp == "Float8E4M3" || Interp == "Float8E4M3FN" ||
5867-
Interp == "Float8E4M3FNUZ" || Interp == "Float8E4M3B11FNUZ" ||
5868-
Interp == "Float8E3M4" || Interp == "Float8E8M0FNU" ||
5869-
Interp == "Float6E3M2FN" || Interp == "Float6E2M3FN" ||
5870-
Interp == "Float4E2M1FN";
5871-
Check(IsKnown, "unsupported interpretation metadata string", Call);
5879+
// Valid interpretation strings: mini-float format names.
5880+
Check(Intrinsic::isValidArbitraryFPFormat(Interp),
5881+
"unsupported interpretation metadata string", Call);
58725882

5873-
// Check rounding mode metadata (argoperand 2)
5883+
// Check rounding mode metadata (argoperand 2).
58745884
auto *RoundingMAV = dyn_cast<MetadataAsValue>(Call.getArgOperand(2));
58755885
Check(RoundingMAV, "missing rounding mode metadata operand", Call);
58765886
auto *RoundingStr = dyn_cast<MDString>(RoundingMAV->getMetadata());
@@ -5882,6 +5892,38 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
58825892
"unsupported rounding mode argument", Call);
58835893
break;
58845894
}
5895+
case Intrinsic::convert_from_arbitrary_fp: {
5896+
// Check that vector element counts are consistent.
5897+
Type *IntTy = Call.getArgOperand(0)->getType();
5898+
Type *ValueTy = Call.getType();
5899+
5900+
if (auto *ValueVecTy = dyn_cast<VectorType>(ValueTy)) {
5901+
auto *IntVecTy = dyn_cast<VectorType>(IntTy);
5902+
Check(IntVecTy,
5903+
"if floating-point operand is a vector, integer operand must also "
5904+
"be a vector",
5905+
Call);
5906+
Check(ValueVecTy->getElementCount() == IntVecTy->getElementCount(),
5907+
"floating-point and integer vector operands must have the same "
5908+
"element count",
5909+
Call);
5910+
}
5911+
5912+
// Check interpretation metadata (argoperand 1).
5913+
auto *InterpMAV = dyn_cast<MetadataAsValue>(Call.getArgOperand(1));
5914+
Check(InterpMAV, "missing interpretation metadata operand", Call);
5915+
auto *InterpStr = dyn_cast<MDString>(InterpMAV->getMetadata());
5916+
Check(InterpStr, "interpretation metadata operand must be a string", Call);
5917+
StringRef Interp = InterpStr->getString();
5918+
5919+
Check(!Interp.empty(), "interpretation metadata string must not be empty",
5920+
Call);
5921+
5922+
// Valid interpretation strings: mini-float format names.
5923+
Check(Intrinsic::isValidArbitraryFPFormat(Interp),
5924+
"unsupported interpretation metadata string", Call);
5925+
break;
5926+
}
58855927
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
58865928
#include "llvm/IR/VPIntrinsics.def"
58875929
#undef BEGIN_REGISTER_VP_INTRINSIC

0 commit comments

Comments
 (0)