[RFC][Standard] Add `std.fptoui` and `std.uitofp` operations

The standard dialect currently offers fptosi and sitofp operations, which convert values between floating point and signed integer types. The Standard-to-LLVM conversion provides one-to-one lowerings from these operations to the corresponding operations in the LLVM dialect. While the LLVM dialect also offers fptoui and uitofp operations, supporting unsigned integer types, no such operations exist in standard.

In our project, we have implemented these “missing” conversions in a separate “standard extension” dialect, supporting a general facility for casting between different numeric types. It seems likely that anyone implementing a generic numeric cast will end up doing something similar.

I propose that std.fptoui and std.uitofp operations should be added, complementary to the existing signed conversions.

See https://reviews.llvm.org/D85557

MLIR has signed, unsigned and singless integers. Does the operation apply to both unsigned and singless integers or not? Why?

Per the original post, the operation applies only to unsigned integers. std.fptosi converts to a signed integer that is hiding in a signless type. So you already have a signless view if you want it. But the standard dialect has nothing on unsigned integers - there is no way to even create unsigned constants. There were documented reasons to not have arithmetic ops, etc. on signed/unsigned integer types, but ops that cast to/from unsigned types (whether to/from fp or signless/signed types) appear fine?

The same question (and I believe the same answer) can be raised with the existing casting operators in the standard dialect and their relation to the LLVM dialect. All integer types are defined as signless in the standard dialect. However, there are certain operations which must respect the original signedness of the value. Casting is one such operation.

Here’s another way to think of this: we can either encode the signedness in the op or in the type. The standard dialect chose to go the same route that LLVM did: encode it in the op. I view this as the same distinction between floating-point & integer data types being encoded in the op or in the type. Again, LLVM & MLIR have chosen to use the op.

I think what’s confusing is that the standard IntegerType does support signed, unsigned, and signless. But we have to remember that the standard types are orthogonal to the standard dialect. (To be clear the only minor confusion to me is the term ‘standard’, which apparently has been a contentious term for awhile now anyways).