I would be interested in learning what the set of used semantics for float-to-int conversion is. If the only two used are 1) undefined behavior if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, then I think it makes sense to expose both of those natively in the IR. If the set is much larger, I think separate intrinsics for each behavior would make sense. It would be nice to get rid of the wasm-specific intrinsic for behavior (2) and replace it with a target-independent intrinsic or IR, since this behavior is not actually particular to WebAssembly. On Mon, Nov 5, 2018 at 2:37 PM Finkel, Hal J. via llvm-dev < llvm-dev at lists.llvm.org> wrote:> > On 11/05/2018 07:26 AM, Nikita Popov via llvm-dev wrote: > > Hi everyone! > > The fptoui/fptosi instructions are currently specified to return a poison > value if the rounded-towards-zero floating point number cannot be > represented by the target integer type. The motivation for this behavior is > that overflowing float to int casts in C are undefined behavior. > > However, many newer languages prefer to have a float to integer cast that > is well-defined for all input values. A commonly chosen semantic is to > saturate towards the minimum and maximum values of the integer type, and > represent NaN values as zero. > > > I think that this is fine, motivationally, and we might even want a > dedicated intrinsic if the IR needed to represent the lowering will, later > in the pipeline, be difficult to pattern match. However, if you want the > casts to be well defined, then you should define their behavior. "Do some > fast thing" is not really a definition, and I don't believe that we should > give target-independent constructs target-dependent behavior. > > -Hal > > An extensive discussion of this issue for the Rust language can be found > at https://github.com/rust-lang/rust/issues/10184. > > Unfortunately, implementing this behavior in an efficient manner is not > easy right now, because depending on the target architecture different > instruction sequences need to be generated. On ARM the vcvt instruction > directly exposes the desired saturation behavior. On X86 good instruction > sequences vary depending on the size of the floating point number, and the > size and signedness of the target integer type. > > I think there are broadly three ways in which the current situation can be > improved: > > 1. Provide a fptoui/fptosi variant to produces target-specific values > instead of a poison value for unrepresentable values. The result would be > whatever is fastest for the given target. > > 2. Provide an intrinsic for saturating floating point to int conversions, > as described above. > > 3. Provide an intrinsic for floating point to int conversions, which > additionally indicates whether the value was representable, similarly to > the existing XXX.with.overflow family of intrinsics. > > I think that point 1 is both the most pressing and the easiest to realize. > This would resolve the immediate soundness problem in Rust (if not in a > great way). Even if Rust specifies that float-to-int conversions are > saturating we'd still want to support this kind of operation for > performance reasons, and it would be preferable if performing a fast > float-to-int conversion did not require dropping into unsafe code. > > The way I would imagine this to work is that fptoui/fptosi gain a flag > similar to add nsw/nuw -- let's call it "fptoui representable" for now. If > the flag is not specified the return value for unrepresentable values is > target-specific. If it is specified, the return value is poison. > (Alternatively the meaning of the flag could be inverted.) > > From a cursory inspection of the code, there should not be too many places > that care about the presence of this flag. The main one is of course > constant folding, but there are probably others (I could imagine that the > Float2Int pass makes assumptions here, but haven't looked too carefully.) > > Point 2 is also important, because specifying saturation as the default > behavior for float-to-int casts is becoming increasingly common. This would > need two new intrinsics, such as: > > iYY llvm.fptoui.sat.fXX.iYY(fXX %a) > iYY llvm.fptosi.sat.fXX.iYY(fXX %a) > > There is some precedent here with the recently introduced llvm.sadd.sat > and llvm.uadd.sat intrinsics for saturating integer addition. The wasm > backend also has custom llvm.wasm.trunc.saturate intrinsics for this > purpose. > > These intrinsics would also need corresponding SelectionDAG nodes. A > generic lowering would use a number of comparison (or min/max) > instructions, while target-specific lowerings will be able to do better > (e.g. single instruction on arm or wasm). > > Point 3 is less important. Having a "with overflow" intrinsic would allow > to easily implement custom handling of unrepresentable values, e.g. to > generate an error in debug builds. The intrinsics would go something like > this: > > {iYY, i1} llvm.fptoui.with.overflow.fXX.iYY(fXX %a) > {iYY, i1} llvm.fptosi.with.overflow.fXX.iYY(fXX %a) > > If the overflow flag is true, the result could be specified to either be > target-specific or undef. > > --- > > I would like to have some feedback on whether there is interest in > improving this area, and in particular: > > a) Whether introducing a flag to control poison vs target-specific value > for fptoui/fptosi is reasonable. Looking through the language reference, it > is somewhat unusual to have target-specific behavior for a fundamental > instruction. > > b) Whether introducing first-class saturating float-to-int cast intrinsics > is reasonable. > > Regards, > Nikita > > > _______________________________________________ > LLVM Developers mailing listllvm-dev at lists.llvm.orghttp://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > > -- > Hal Finkel > Lead, Compiler Technology and Programming Languages > Leadership Computing Facility > Argonne National Laboratory > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181105/a6b1aa29/attachment.html>
On Mon, 5 Nov 2018 at 14:41, Thomas Lively via llvm-dev <llvm-dev at lists.llvm.org> wrote:> I would be interested in learning what the set of used semantics for float-to-int conversion is. If the only two used are 1) undefined behavior if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, then I think it makes sense to expose both of those natively in the IR.Javascript has some truly bizarre modulo behaviour, though it's so far from what anyone would actively choose I'm not sure it should affect our decision for a canonical defined conversion. Cheers. Tim.
> On Nov 5, 2018, at 2:41 PM, Thomas Lively via llvm-dev <llvm-dev at lists.llvm.org> wrote: > > I would be interested in learning what the set of used semantics for float-to-int conversion is. If the only two used are 1) undefined behavior if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, then I think it makes > sense to expose both of those natively in the IR. If the set is much larger, I think separate intrinsics for each behavior would make sense. It would be nice to get rid of the wasm-specific intrinsic for behavior (2) and replace it with a target-independent intrinsic or IR, since this behavior is not actually particular to WebAssembly.For example: - X86 returns the "indefinite integer value (80000000H)" (regardless of overflow in the positive or negative direction) - AArch64 saturates towards int_min/int_max So no matter what semantic you pick, code generation will require extra instructions on one of the two architectures... - Matthias> > On Mon, Nov 5, 2018 at 2:37 PM Finkel, Hal J. via llvm-dev <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote: > > On 11/05/2018 07:26 AM, Nikita Popov via llvm-dev wrote: >> Hi everyone! >> >> The fptoui/fptosi instructions are currently specified to return a poison value if the rounded-towards-zero floating point number cannot be represented by the target integer type. The motivation for this behavior is that overflowing float to int casts in C are undefined behavior. >> >> However, many newer languages prefer to have a float to integer cast that is well-defined for all input values. A commonly chosen semantic is to saturate towards the minimum and maximum values of the integer type, and represent NaN values as zero. > > I think that this is fine, motivationally, and we might even want a dedicated intrinsic if the IR needed to represent the lowering will, later in the pipeline, be difficult to pattern match. However, if you want the casts to be well defined, then you should define their behavior. "Do some fast thing" is not really a definition, and I don't believe that we should give target-independent constructs target-dependent behavior. > > -Hal > >> An extensive discussion of this issue for the Rust language can be found at https://github.com/rust-lang/rust/issues/10184 <https://github.com/rust-lang/rust/issues/10184>. >> >> Unfortunately, implementing this behavior in an efficient manner is not easy right now, because depending on the target architecture different instruction sequences need to be generated. On ARM the vcvt instruction directly exposes the desired saturation behavior. On X86 good instruction sequences vary depending on the size of the floating point number, and the size and signedness of the target integer type. >> >> I think there are broadly three ways in which the current situation can be improved: >> >> 1. Provide a fptoui/fptosi variant to produces target-specific values instead of a poison value for unrepresentable values. The result would be whatever is fastest for the given target. >> >> 2. Provide an intrinsic for saturating floating point to int conversions, as described above. >> >> 3. Provide an intrinsic for floating point to int conversions, which additionally indicates whether the value was representable, similarly to the existing XXX.with.overflow family of intrinsics. >> >> I think that point 1 is both the most pressing and the easiest to realize. This would resolve the immediate soundness problem in Rust (if not in a great way). Even if Rust specifies that float-to-int conversions are saturating we'd still want to support this kind of operation for performance reasons, and it would be preferable if performing a fast float-to-int conversion did not require dropping into unsafe code. >> >> The way I would imagine this to work is that fptoui/fptosi gain a flag similar to add nsw/nuw -- let's call it "fptoui representable" for now. If the flag is not specified the return value for unrepresentable values is target-specific. If it is specified, the return value is poison. (Alternatively the meaning of the flag could be inverted.) >> >> From a cursory inspection of the code, there should not be too many places that care about the presence of this flag. The main one is of course constant folding, but there are probably others (I could imagine that the Float2Int pass makes assumptions here, but haven't looked too carefully.) >> >> Point 2 is also important, because specifying saturation as the default behavior for float-to-int casts is becoming increasingly common. This would need two new intrinsics, such as: >> >> iYY llvm.fptoui.sat.fXX.iYY(fXX %a) >> iYY llvm.fptosi.sat.fXX.iYY(fXX %a) >> >> There is some precedent here with the recently introduced llvm.sadd.sat and llvm.uadd.sat intrinsics for saturating integer addition. The wasm backend also has custom llvm.wasm.trunc.saturate intrinsics for this purpose. >> >> These intrinsics would also need corresponding SelectionDAG nodes. A generic lowering would use a number of comparison (or min/max) instructions, while target-specific lowerings will be able to do better (e.g. single instruction on arm or wasm). >> >> Point 3 is less important. Having a "with overflow" intrinsic would allow to easily implement custom handling of unrepresentable values, e.g. to generate an error in debug builds. The intrinsics would go something like this: >> >> {iYY, i1} llvm.fptoui.with.overflow.fXX.iYY(fXX %a) >> {iYY, i1} llvm.fptosi.with.overflow.fXX.iYY(fXX %a) >> >> If the overflow flag is true, the result could be specified to either be target-specific or undef. >> >> --- >> >> I would like to have some feedback on whether there is interest in improving this area, and in particular: >> >> a) Whether introducing a flag to control poison vs target-specific value for fptoui/fptosi is reasonable. Looking through the language reference, it is somewhat unusual to have target-specific behavior for a fundamental instruction. >> >> b) Whether introducing first-class saturating float-to-int cast intrinsics is reasonable. >> >> Regards, >> Nikita >> >> >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev> > > -- > Hal Finkel > Lead, Compiler Technology and Programming Languages > Leadership Computing Facility > Argonne National Laboratory > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev> > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181105/212affe4/attachment.html>
That said, 1) I also think IR instructions (or builtins) must not change semantics based on the compilation target. 2) If anything, we could provide several builtins for the different target behaviors and let the frontend choose a performant one (assuming the frontend is aware of the target). We could even use TargetTransformInfo to let targets communicate back what is fastest. 3) The solution in 2) seems quite complex to me, we may just want to go for saturation behavior and let people take a small hit on X86. That's the price you pay if you eliminate undefined behavior... - Matthias> On Nov 5, 2018, at 3:06 PM, Matthias Braun via llvm-dev <llvm-dev at lists.llvm.org> wrote: > > > >> On Nov 5, 2018, at 2:41 PM, Thomas Lively via llvm-dev <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote: >> >> I would be interested in learning what the set of used semantics for float-to-int conversion is. If the only two used are 1) undefined behavior if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, then I think it makes >> sense to expose both of those natively in the IR. If the set is much larger, I think separate intrinsics for each behavior would make sense. It would be nice to get rid of the wasm-specific intrinsic for behavior (2) and replace it with a target-independent intrinsic or IR, since this behavior is not actually particular to WebAssembly. > > For example: > - X86 returns the "indefinite integer value (80000000H)" (regardless of overflow in the positive or negative direction) > - AArch64 saturates towards int_min/int_max > > So no matter what semantic you pick, code generation will require extra instructions on one of the two architectures... > > - Matthias > >> >> On Mon, Nov 5, 2018 at 2:37 PM Finkel, Hal J. via llvm-dev <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote: >> >> On 11/05/2018 07:26 AM, Nikita Popov via llvm-dev wrote: >>> Hi everyone! >>> >>> The fptoui/fptosi instructions are currently specified to return a poison value if the rounded-towards-zero floating point number cannot be represented by the target integer type. The motivation for this behavior is that overflowing float to int casts in C are undefined behavior. >>> >>> However, many newer languages prefer to have a float to integer cast that is well-defined for all input values. A commonly chosen semantic is to saturate towards the minimum and maximum values of the integer type, and represent NaN values as zero. >> >> I think that this is fine, motivationally, and we might even want a dedicated intrinsic if the IR needed to represent the lowering will, later in the pipeline, be difficult to pattern match. However, if you want the casts to be well defined, then you should define their behavior. "Do some fast thing" is not really a definition, and I don't believe that we should give target-independent constructs target-dependent behavior. >> >> -Hal >> >>> An extensive discussion of this issue for the Rust language can be found at https://github.com/rust-lang/rust/issues/10184 <https://github.com/rust-lang/rust/issues/10184>. >>> >>> Unfortunately, implementing this behavior in an efficient manner is not easy right now, because depending on the target architecture different instruction sequences need to be generated. On ARM the vcvt instruction directly exposes the desired saturation behavior. On X86 good instruction sequences vary depending on the size of the floating point number, and the size and signedness of the target integer type. >>> >>> I think there are broadly three ways in which the current situation can be improved: >>> >>> 1. Provide a fptoui/fptosi variant to produces target-specific values instead of a poison value for unrepresentable values. The result would be whatever is fastest for the given target. >>> >>> 2. Provide an intrinsic for saturating floating point to int conversions, as described above. >>> >>> 3. Provide an intrinsic for floating point to int conversions, which additionally indicates whether the value was representable, similarly to the existing XXX.with.overflow family of intrinsics. >>> >>> I think that point 1 is both the most pressing and the easiest to realize. This would resolve the immediate soundness problem in Rust (if not in a great way). Even if Rust specifies that float-to-int conversions are saturating we'd still want to support this kind of operation for performance reasons, and it would be preferable if performing a fast float-to-int conversion did not require dropping into unsafe code. >>> >>> The way I would imagine this to work is that fptoui/fptosi gain a flag similar to add nsw/nuw -- let's call it "fptoui representable" for now. If the flag is not specified the return value for unrepresentable values is target-specific. If it is specified, the return value is poison. (Alternatively the meaning of the flag could be inverted.) >>> >>> From a cursory inspection of the code, there should not be too many places that care about the presence of this flag. The main one is of course constant folding, but there are probably others (I could imagine that the Float2Int pass makes assumptions here, but haven't looked too carefully.) >>> >>> Point 2 is also important, because specifying saturation as the default behavior for float-to-int casts is becoming increasingly common. This would need two new intrinsics, such as: >>> >>> iYY llvm.fptoui.sat.fXX.iYY(fXX %a) >>> iYY llvm.fptosi.sat.fXX.iYY(fXX %a) >>> >>> There is some precedent here with the recently introduced llvm.sadd.sat and llvm.uadd.sat intrinsics for saturating integer addition. The wasm backend also has custom llvm.wasm.trunc.saturate intrinsics for this purpose. >>> >>> These intrinsics would also need corresponding SelectionDAG nodes. A generic lowering would use a number of comparison (or min/max) instructions, while target-specific lowerings will be able to do better (e.g. single instruction on arm or wasm). >>> >>> Point 3 is less important. Having a "with overflow" intrinsic would allow to easily implement custom handling of unrepresentable values, e.g. to generate an error in debug builds. The intrinsics would go something like this: >>> >>> {iYY, i1} llvm.fptoui.with.overflow.fXX.iYY(fXX %a) >>> {iYY, i1} llvm.fptosi.with.overflow.fXX.iYY(fXX %a) >>> >>> If the overflow flag is true, the result could be specified to either be target-specific or undef. >>> >>> --- >>> >>> I would like to have some feedback on whether there is interest in improving this area, and in particular: >>> >>> a) Whether introducing a flag to control poison vs target-specific value for fptoui/fptosi is reasonable. Looking through the language reference, it is somewhat unusual to have target-specific behavior for a fundamental instruction. >>> >>> b) Whether introducing first-class saturating float-to-int cast intrinsics is reasonable. >>> >>> Regards, >>> Nikita >>> >>> >>> _______________________________________________ >>> LLVM Developers mailing list >>> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev> >> >> -- >> Hal Finkel >> Lead, Compiler Technology and Programming Languages >> Leadership Computing Facility >> Argonne National Laboratory >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev> >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev>-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181105/6df4bb97/attachment-0001.html>
On Mon, Nov 5, 2018 at 11:41 PM Thomas Lively <tlively at google.com> wrote:> I would be interested in learning what the set of used semantics for > float-to-int conversion is. If the only two used are 1) undefined behavior > if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, > then I think it makes sense to expose both of those natively in the IR. If > the set is much larger, I think separate intrinsics for each behavior would > make sense. It would be nice to get rid of the wasm-specific intrinsic for > behavior (2) and replace it with a target-independent intrinsic or IR, > since this behavior is not actually particular to WebAssembly. >Here is how various languages behave with unrepresentable float-to-int casts: Undefined Behavior: C, C++, D, Rust (unintentionally) Implementation-Defined Behavior: C#, Go Runtime Error: Swift, Julia Saturation: Java, Rust (planned) Modular Reduction: JavaScript, PHP There are some caveats here (often there is more than one way to do the conversion, etc), but I think this gives the general idea. The "Undefined Behavior" category is covered by the existing fptosi/fptoui instructions. Based on the responses, I understand that having a flag for "Implementation-Defined Behavior" is not well received (and I guess using platform intrinsics would be an alternative here). To support the saturation behavior, I have been working on a pair of llvm.fptosi.sat / llvm.fptoui.sat intrinsics. My current implementation can be found at https://reviews.llvm.org/D54696. I'll work on splitting this up into more reviewable parts, though if there's any early feedback on the implementation approach, I'd appreciate that. Regards, Nikita -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181119/8f857dea/attachment.html>
On Mon, Nov 19, 2018 at 1:02 PM Nikita Popov <nikita.ppv at gmail.com> wrote:> On Mon, Nov 5, 2018 at 11:41 PM Thomas Lively <tlively at google.com> wrote: > >> I would be interested in learning what the set of used semantics for >> float-to-int conversion is. If the only two used are 1) undefined behavior >> if unrepresentable and 2) saturate to int_{min,max} with NaN going to zero, >> then I think it makes sense to expose both of those natively in the IR. If >> the set is much larger, I think separate intrinsics for each behavior would >> make sense. It would be nice to get rid of the wasm-specific intrinsic for >> behavior (2) and replace it with a target-independent intrinsic or IR, >> since this behavior is not actually particular to WebAssembly. >> > > Here is how various languages behave with unrepresentable float-to-int > casts: > > Undefined Behavior: C, C++, D, Rust (unintentionally) > Implementation-Defined Behavior: C#, Go > Runtime Error: Swift, Julia > Saturation: Java, Rust (planned) > Modular Reduction: JavaScript, PHP > > There are some caveats here (often there is more than one way to do the > conversion, etc), but I think this gives the general idea. > > The "Undefined Behavior" category is covered by the existing fptosi/fptoui > instructions. Based on the responses, I understand that having a flag for > "Implementation-Defined Behavior" is not well received (and I guess using > platform intrinsics would be an alternative here). > > To support the saturation behavior, I have been working on a pair of > llvm.fptosi.sat / llvm.fptoui.sat intrinsics. My current implementation can > be found at https://reviews.llvm.org/D54696. I'll work on splitting this > up into more reviewable parts, though if there's any early feedback on the > implementation approach, I'd appreciate that. > > Regards, > Nikita >Forgot to post this earlier, I've created https://reviews.llvm.org/D54749 with the first step towards supporting saturating float-to-int casts, including new intrinsics and baseline DAG expansion (which generates horrible code on X86). Would appreciate if someone could take a look :) Regards, Nikita -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181212/2239106a/attachment.html>