This is an archive of the discontinued LLVM Phabricator instance.

FloatingPointMode: Use -1 for "Dynamic"
Needs ReviewPublic

Authored by arsenm on Aug 3 2023, 4:50 AM.

Details

Summary

FLT_ROUNDS says -1 is used for "the default rounding direction is not
known". The previous 7 was taking away options in the
"implementation-defined behavior" range if you just wanted to extend
the enum.

AMDGPU has 2 separately controllable rounding modes that change
different fp types. I want to stick to the standard values in the case
the modes are the same, and use the extended range for cases where the
two are different. Dodging this gap in the enum value required
defining the AMDGPU target specific values in a weird way with strange
conversion code to handle it (see https://reviews.llvm.org/D153257).

Diff Detail

Event Timeline

arsenm created this revision.Aug 3 2023, 4:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 3 2023, 4:50 AM
arsenm requested review of this revision.Aug 3 2023, 4:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 3 2023, 4:50 AM
Herald added a subscriber: wdng. · View Herald Transcript
foad added inline comments.Aug 3 2023, 5:07 AM
llvm/include/llvm/ADT/FloatingPointMode.h
39

Lost the ///< comment here.

41

Does ///< work before the field name?

arsenm updated this revision to Diff 546815.Aug 3 2023, 5:25 AM

Rounding mode is presented in FPOptions with 3 bits, so there is only 8 values available for particular modes. 5 of them, which are specified in IEEE-754, are listed in RoundingMode. Dynamic (which is -1 in 3-bit numbers) is not a real rounding mode, it represents rounding mode unknown at compiler time. RoundingMode::Invalid is not a mode at all, it is used to represent unspecified value at compile-time and can be eliminated by using things like std::optional. In 3 bits it would have the same value as Dynamic, but it is not a problem, because Invalid never appears in AST and IR.

Probably Dynamic is what you need. It prevents from constant folding and other transformations that rely on particular rounding mode and does not restrict actual rounding modes used in runtime. What prevents from using this mode for your case?

Rounding mode is presented in FPOptions with 3 bits, so there is only 8 values available for particular modes. 5 of them, which are specified in IEEE-754, are listed in RoundingMode. Dynamic (which is -1 in 3-bit numbers) is not a real rounding mode,

But it is a spec'd value as -1 for FLT_ROUNDS

RoundingMode::Invalid is not a mode at all, it is used to represent unspecified value at compile-time and can be eliminated by using things like std::optional. In 3 bits it would have the same value as Dynamic, but it is not a problem, because Invalid never appears in AST and IR.

Right it's just filler here

Probably Dynamic is what you need. It prevents from constant folding and other transformations that rely on particular rounding mode and does not restrict actual rounding modes used in runtime. What prevents from using this mode for your case?

I can do better by reporting something meaningful, two different modes is not unknown. The enum here should just be exactly equal to the FLT_ROUNDS values and not pick a random other number, I just need the wrong value for Dynamic to get out of the way to avoid creating additional wrappers

Rounding mode is presented in FPOptions with 3 bits, so there is only 8 values available for particular modes. 5 of them, which are specified in IEEE-754, are listed in RoundingMode. Dynamic (which is -1 in 3-bit numbers) is not a real rounding mode,

But it is a spec'd value as -1 for FLT_ROUNDS

It is no more than failure indicator for this function or macro. fegetround may use any negative value for this purpose. -1 does not represent any rounding mode, just like EOF does not represent any character in a stream.

Probably Dynamic is what you need. It prevents from constant folding and other transformations that rely on particular rounding mode and does not restrict actual rounding modes used in runtime. What prevents from using this mode for your case?

I can do better by reporting something meaningful, two different modes is not unknown. The enum here should just be exactly equal to the FLT_ROUNDS values and not pick a random other number, I just need the wrong value for Dynamic to get out of the way to avoid creating additional wrappers

Support of rounding mode in C standard is based on IEEE-754 model, where rounding mode is a global state and affects all FP operations. The case of two rounding modes does not fit this model. So in C/C++ you anyway need to invent special tools for setting this or that rounding mode or reading them. If static rounding mode is not needed, IEEE-754 rounding mode could be represented by Dynamic value.

In IR there are more possibilities to represent many rounding modes. Each constrained intrinsic call contains rounding mode and that mode may be different for different FP types. Actually this model can support the general case. For example, rounding mode for one type can be static but for the other type it can be dynamic. There must be intrinsic functions that set/get rounding mode for different types.

It looks like adding special bultin functions to get/set rounding mode for different types is enough to support rounding in AMDGPU. In any case IEEE-754 rounding mode should be honored, which means that fegetround and FLT_ROUNDS probably should return negative value, and fesetround probably should set all rounding modes. The difference between Dynamic and -1 does not matter because Dynamic can never be an argument of rounding mode type and Invalid (-1) is an error indicator and must not be treated as rounding mode.

arsenm added a comment.Aug 4 2023, 2:46 PM

Support of rounding mode in C standard is based on IEEE-754 model, where rounding mode is a global state and affects all FP operations. The case of two rounding modes does not fit this model. So in C/C++ you anyway need to invent special tools for setting this or that rounding mode or reading them. If static rounding mode is not needed, IEEE-754 rounding mode could be represented by Dynamic value.

Correct, I'm not planning on creating special "standard looking" tools. I just want the value in the target defined range rather than a black box.

In IR there are more possibilities to represent many rounding modes. Each constrained intrinsic call contains rounding mode and that mode may be different for different FP types. Actually this model can support the general case. For example, rounding mode for one type can be static but for the other type it can be dynamic. There must be intrinsic functions that set/get rounding mode for different types.

The raw target intrinsic to read the mode register works. Once you're in the target range you know you have to do something with target operations

It looks like adding special bultin functions to get/set rounding mode for different types is enough to support rounding in AMDGPU. In any case IEEE-754 rounding mode should be honored, which means that fegetround and FLT_ROUNDS probably should return negative value, and fesetround probably should set all rounding modes. The difference between Dynamic and -1 does not matter because Dynamic can never be an argument of rounding mode type and Invalid (-1) is an error indicator and must not be treated as rounding mode.

My interpretation is fesetround of standard values would set all modes to be the same. Once you're outside of the range it would work correctly to consume the same target defined values. "Could not determine" is the same as dynamic, so this should just use the standard -1 value instead of 7 just to fit in a clang bitfield

ping. This enum should just match FLT_ROUNDS and designing ABI around whatever this was doing doesn't really make sense

Dynamic cannot have value -1, its value must fits 3 bits. Some targets encode rounding mode in instructions, RISCV is an example. It allows five "real" rounding modes, enlisted now in RoundingMode to be specified in a special field or FP instruction. This field also can contain a distinct value that instructs the processor to take rounding mode from a special register. This is a "dynamic" rounding mode in contract to the "static" modes, specified by one of "real" values. When #pragma STC FENV_ACCESS ON is specified, FP operations must use the "dynamic" rounding mode, - they have Dynamic in FPOptions of their AST nodes.