The NoFPExcept bit in SDNodeFlags currently defaults to true, unlike all other such flags. This is a problem, because it implies that all code that transforms SDNodes without copying flags can introduce a correctness bug, not just a missed optimization.
This patch changes the default to false. This requires moving the setting of the (No)FPExcept flag for constrained intrinsics from the visitConstrainedIntrinsic routine to the generic visit routine at the place where the other flags are set, or else the intersectFlagsWith call would erase the NoFPExcept flag again.
In order to avoid making non-strict FP code worse, whenever SelectionDAGISel::SelectCodeCommon is called on an original node that can not raise FP exceptions, it will preserve this property on all results nodes generated, by setting the NoFPExcept flag on those result nodes that would otherwise be considered as raising an FP exception.
To check whether or not an SD node should be considered as raising an FP exception, the following logic applies:
- For machine nodes, check the mayRaiseFPException property of the underlying MI instruction
- For regular nodes, check isStrictFPOpcode
- For target nodes, check a newly introduced isTargetStrictFPOpcode
The latter is implemented by reserving a range of target opcodes, similarly to how memory opcodes are identified. (Note that there a bit of a quirk in identifying target nodes that are both memory nodes and strict FP nodes. To simplify the logic, right now all target memory nodes are automatically also considered strict FP nodes -- this could be fixed by adding one more range.)
I've updated SystemZ and X86 (the only targets currently defining target strict FP nodes) accordingly.
This patch causes a number of changes to X86 test cases, because instructions are now (correctly) marked fpexcept at the MI level, where this was missed by old code.
Note that the MI-level fpexcept flag is not inverted by this patch. For correctness reasons, this should still be done as well; I'm working on a follow-on patch.
Shouldn't this also check for < FIRST_TARGET_MEMORY_OPCODE?