This patch includes the necessary code for converting between a fixed point type and integer. This also includes constant expression evaluation for conversions with these types.
Can most of this reasonably be a method on APFixedPoint? (And likewise for CK_IntegralToFixedPoint.) If nothing else, I suspect you are going to want these when it comes to things like the compound assignment operators, which do implicit conversions internally that aren't directly expressed in the AST.
The Result < 0 is more clearly expressed as Result.isNegative() I think.
I think this block can be simplified significantly by simply rounding up before conversion. So, something like:
%lt = icmp slt %val, 0 %rounded = add %val, lowBits(Scale) %sel = select %lt, %rounded, %val ... rescale/resize ...
Seems like a lot of logic in these blocks is duplicated from the code in ExprConstant.
Ah, so I ran into something similar with the patch preceding this in APFixedPoint::convert(). isNegative() is a method of APInt which doesn't care about signage. It just checks if the last bit is set. Result < 0 calls APSInt::operator<() which cares about the sign and checks if this signed int is less than zero.
have no big problem with this, but if Result.isNegative() is more readable, I could also add Result.isSigned() which together effectively does the same thing as Result < 0.
Compressed them into APFixedPoint::convertToInt() and APFixedPoint::getFromIntValue()
Yeah. I moved into APFixedPoint::getFromIntValue() to simplify this.
This makes sense, but you're already checking if the value is signed in the line above, so it shouldn't be an issue.
There are no tests here for what you get if you convert an integer to a fixed-point type with a larger integral part than the integer has.
Conversions like this are a bit odd. There shouldn't be a need to upsize/upscale the container before the saturation, should there?
Oh I forgot to submit the comments.
Ah, forgot about that.
Added to the end of TestIntToFixedPoint
I see. You're saying that we can just check directly if the value exceeds 255 (or goes under -256) since the range of target values can always fit in the range of source values. Therefore we do not need to cast up since the only reason we would need to is if converting to a type with a greater source range.
In this case, we could technically have a special case for integers where I think we can perform the saturation checks without the initial sign extension. I think it might be simpler though if in EmitFixedPointConversion, we treat an integer as a 'zero-scale fixed point number'. I think the reason the upsizing occurs in the first place is so that we satisfy the first FX conversion rule of calculating the result with full precision of both operands.
That's right. Though, for integer to fixed-point conversion, I don't think you ever need to upcast first; either the integer is larger than or equal to the integral part of the fixed-point type, in which case we can check the magnitude in the type as is, or it's smaller, and we don't have to do any saturation.
Isn't this already the case? The semantics for an integer type are fetched as a zero scale fixed-point type and used that way (except when the target is an integer due to the rounding requirement).
I see. I think this would be more of a matter then of when checking for saturation, we either should check against the source value after resizing and scaling (container), or the source by itself before resizing and scaling. Actually, I think that when comparing saturation against the source value, we could save an instruction since we can just generate a constant to compare the source against instead of comparing against a potentially shifted value. I think this could work when converting from fixed point types as well.
With saturation conversion, (if the target scale >= src scale) currently we could generate up to 7 instructions:
I think we don't need either the first or last resize if the constants that we check against are the respective max's/min's of the target type against the source. I think this deserves a patch on it's own though since it could change a bunch of tests that depend on EmitFixedPointConversion.
What I meant by this was that we are already doing the right thing in that we calculate the result with the full precision of both operands.
I think the patch demonstrated to me that this emission can't be optimized in general without breaking the minmax pattern on the saturation, and that is very useful in some cases.
What I think I'm concerned about is conversions like int -> _Sat _Fract, where there really is no point to upscaling at all, since the resulting will either be -1, 0 or ~0.999.
I think upscaling is also necessary in this case if we decide to keep the minmax pattern for all conversion cases, otherwise we'd still be comparing against the result:
%0 = load i32, i32* %i, align 4 %1 = icmp sgt i32 %0, 1 %satmax = select i1 %1, i32 32767, i32 %0 %2 = icmp slt i32 %0, 1 %satmin = select i1 %2, i32 -32768, i32 %satmax store i16 %resize1, i16* %sat_f, align 2
However, this takes only 6 instructions whereas the pattern we currently have takes 9:
%0 = load i32, i32* %i, align 4 %resize = sext i32 %0 to i47 %upscale = shl i47 %resize, 15 %1 = icmp sgt i47 %upscale, 32767 %satmax = select i1 %1, i47 32767, i47 %upscale %2 = icmp slt i47 %satmax, -32768 %satmin = select i1 %2, i47 -32768, i47 %satmax %resize1 = trunc i47 %satmin to i16 store i16 %resize1, i16* %sat_f, align 2
We could say that for specific cases, we compare against the source value and others we do minmax.
A couple tweaks, but otherwise LGTM.
This is super-picky, but please either just say "integral" (without an article) or spell out "an integral type".
Please specify what happens to the overflow flag if there's a fractional component.
Perhaps we should verify that we do not mess up signed values when using the -fpadding-on-unsigned-fixed-point option (having CHECK, DEFAULT and SAME as check prefixes)?
(nit: I also see that we now use different names for this check prefixes in different test files, which could be confusing. Why is it called SAME here?)
A little bit confusing to be with this mix of having checks left-aligned (on separate lines) and some checks appended like this.
(I'm not so familiar with clang tests, so maybe it is common to have the FileCheck checks at the end of the line. But I've never seen that in llvm.)
Sorry forgot to update these prefixes.
Will change this, but would be easier for me if it was done after this commit.