This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Avoid undef result due to promotion of FPOWI exponent
AbandonedPublic

Authored by bjope on May 21 2021, 6:30 AM.

Details

Summary

The 64-bit RISCV target has no legal i32 type. So when SelectionDAG
is legalizing the types for FPOWI the exponent is promoted to i64.
However, the FPOWI/STRICT_FPOWI are defined as having undefined
result if the exponent is larger than i32 (it should probably say
"if the exponent is larger than sizeof(int) for the target" as it
shold be possible to lower those nodes to RTLIB::POWI libcalls and
those runtime library functions is using "int" as input arguments).

This patch can be seen as a workaround to avoid that we promote
the exponent to i64 (making the result undefined). As a simple
solution we expand FPOWI/STRICT_FPOWI into SINT_TO_FP+FPOW. This
is the same rewrite as normally done by LegalizeDAG when the
RTLIB::POWI libcalls aren't allowed.

I leave it as a future FIXME to implement legalization/lowering
of FPOWI/STRICT_FPOWI into using RTLIB::POWI libcalls again. Someone
that knows about RISCV and calling conventions can perhaps figure
out how to do that properly.

Diff Detail

Event Timeline

bjope created this revision.May 21 2021, 6:30 AM
bjope requested review of this revision.May 21 2021, 6:30 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 21 2021, 6:30 AM
Herald added a subscriber: MaskRay. · View Herald Transcript

Where is it documented that larger than i32 is undefined? I see this in ISDOpcodes.def

For FPOWI, the result is undefined if if the integer operand doesn't fit into 32 bits.

That sounds more like it’s talking about the range of the value than the type. So why isn’t it ok to sign extend i32 to i64?

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

bjope added a comment.May 21 2021, 8:47 AM

Where is it documented that larger than i32 is undefined? I see this in ISDOpcodes.def

For FPOWI, the result is undefined if if the integer operand doesn't fit into 32 bits.

That sounds more like it’s talking about the range of the value than the type. So why isn’t it ok to sign extend i32 to i64?

Right, one could argue that the value fits if doing a sign-extend. Then this patch might be a bit harsh as it regress the RISCV lowering without actually having depended on that noone folded the FPOWI to undef (as that only would be allowed if the value potentially could be out-of-range).

bjope added a comment.May 21 2021, 8:55 AM

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

Since it is a bit fragile to allow the generic promotion to promote the exponenet to a type larger than "sizeof(int)" I was looking for some way to handle this special case for RISCV64 (as that is the only target I've found that uses the generic promotion to implement the calling convention ABI sign-extend).

Before I uploaded this patch I made some attempts trying to implement this using some other hack. But I didn't feel confident with those hacks. Maybe I was hooking into the wrong place, but I guess one need to consider the soft floats (or not releveant for RISCV?) and strict fp (or not?) . And one still need to legalize the fp operand? And the result? So one would need to do all that using some custom lowering, right?

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

Since it is a bit fragile to allow the generic promotion to promote the exponenet to a type larger than "sizeof(int)" I was looking for some way to handle this special case for RISCV64 (as that is the only target I've found that uses the generic promotion to implement the calling convention ABI sign-extend).

It's quite likely the sign extend was added to LegalizeIntegerTypes specifically for RISCV.

Before I uploaded this patch I made some attempts trying to implement this using some other hack. But I didn't feel confident with those hacks. Maybe I was hooking into the wrong place, but I guess one need to consider the soft floats (or not releveant for RISCV?) and strict fp (or not?) . And one still need to legalize the fp operand? And the result? So one would need to do all that using some custom lowering, right?

RISCV does have soft float. SoftenFloatRes_FPOWI probably ends up promoting the type when it goes through makeLibCall. So it be ok already?

bjope added a comment.May 21 2021, 9:29 AM

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

Ok I missed the other patches this is linked to. The RISCV64 ABI is to pass int as an i64 that has been sign extended which is what we were doing.

So should we Custom type legalize to the exact sequence we were using before?

Since it is a bit fragile to allow the generic promotion to promote the exponenet to a type larger than "sizeof(int)" I was looking for some way to handle this special case for RISCV64 (as that is the only target I've found that uses the generic promotion to implement the calling convention ABI sign-extend).

It's quite likely the sign extend was added to LegalizeIntegerTypes specifically for RISCV.

Before I uploaded this patch I made some attempts trying to implement this using some other hack. But I didn't feel confident with those hacks. Maybe I was hooking into the wrong place, but I guess one need to consider the soft floats (or not releveant for RISCV?) and strict fp (or not?) . And one still need to legalize the fp operand? And the result? So one would need to do all that using some custom lowering, right?

RISCV does have soft float. SoftenFloatRes_FPOWI probably ends up promoting the type when it goes through makeLibCall. So it be ok already?

The problem this patch is intended to solve is that without it one would end up failing on the assert in DAGTypeLegalizer::PromoteIntOp_FPOWI that I planned to add in D99439.
So one would need to make sure we do something before type legalization is promoting the non-legal i32 operand in the FPOWI.
Btw, if just skipping the assert for RISCV one would later end up in the new diagnostic being added in LegalizeDAG in D99439. So I think one need to custom lower to a libcall quite early for RISCV if we want the diagnostics related to the exponent type.

Another idea is to skip adding those checks (risking miscompiles, relying on that targets are implementing regression tests that validate that the lowering into libcalls works as expected). I basically added those diagnostics based on a review comment from @efriedma. But I guess we risk using the wrong type for any libcall, so I'm not sure adding diagnostics specifically for FPOWI is doing much difference generally?

I don't think this is the right approach... in particular, messing with target-specific code means that every target that doesn't have 32-bit registers would need to explicitly handle this.

What we should be doing is changing DAGTypeLegalizer::PromoteIntOp_FPOWI so it doesn't generate an FPOWI with a 64-bit operand, so we don't have an issue in the first place. We can generate the powi libcall from there, I think.

bjope added a comment.May 21 2021, 3:38 PM

I don't think this is the right approach... in particular, messing with target-specific code means that every target that doesn't have 32-bit registers would need to explicitly handle this.

What we should be doing is changing DAGTypeLegalizer::PromoteIntOp_FPOWI so it doesn't generate an FPOWI with a 64-bit operand, so we don't have an issue in the first place. We can generate the powi libcall from there, I think.

Yes. After digging around a bit I think I got something that hopefully looks ok. Took me awhile to understand that I shouldn't need to care about legalization of the result and fp operand (because those should have been legalized already when we get to type legalizing the exponent operand). And I also realized that I can provide the original (not promoted) operand to TargetLowering::makeLibCall and then lowerCallTo will handle the situation according to the calling convention (such as promoting using sign-extend for 64-bit RISCV).

So I created D102950 that hopefully can replace this patch by creating the libcall already in DAGTypeLegalizer::PromoteIntOp_FPOWI.