ebevhan added inline comments.

================
Comment at: lib/Basic/FixedPoint.cpp:53
+    // We can overflow here
+    unsigned ShiftAmt = DstScale - Scale;
+    if (Val < 0 && Val.countLeadingOnes() >= ShiftAmt)
----------------
ebevhan wrote:
> I think saturation can be modeled a bit better. It should be possible to do 
> the overflow check/saturation once instead of twice, and also have it fit in 
> better with the other conversions.
> 
> Saturation on a value is essentially checking whether all bits above and 
> including a certain bit are all the same, and 'clamping' to either the 
> minimum (the mask) or maximum (inverse of the mask) if not.
> ```
> // Saturate Value to SatWidth. This will clamp Value at the signed min/max of 
> a value that is SatWidth long.
> Saturate(SatWidth):
>   Mask = highBits(Width, SatWidth + 1)
>   Masked = Value & Mask
>   Result = Value
>   if (Masked == Mask || Masked == 0) {
>     if (Masked.isNegative())
>       Result = Mask
>     else
>       Result = ~Mask
>   }
> ```
> This cannot be done on the value in the source scale, since upscaling after 
> clamping would produce an incorrect value - we would shift in 0's from the 
> right even though we should have saturated all bits completely. Also, we 
> cannot upscale without first extending or we might shift out bits on the left 
> that could affect saturation.
> 
> One thing to note is that (I'm ***pretty sure*** this is the case) fractional 
> bits cannot affect saturation. This means that we can find a common scale, 
> then perform the saturation operation, and then resize, and the value should 
> just fall into place. Basically:
>   # Upscale if necessary, but extend first to ensure that we don't drop any 
> bits on the left. Do this by resizing to `SrcWidth - SrcScale + 
> std::max(SrcScale, DstScale)` and then upscaling normally by `DstScale - 
> SrcScale`.
>   # Downscale if necessary by `SrcScale - DstScale`. (I think; in our 
> downstream, we saturate first and then downscale, but we also assume that 
> saturation can only occur on _Fract, and doing saturation first makes the 
> saturation width calculation a bit messier because it will be a `max` 
> expression. I'm unsure if the order can be changed.)
>   # At this point, the scale of the value should be `DstScale`. Saturate with 
> `Saturate(DstWidth)`.
>   # Now the value should be in range for the new width, and will be at the 
> right scale as well. Resize with `extOrTrunc(DstWidth)`.
>   # (Also; if the result was negative and the dest type is unsigned, just 
> make the result zero here instead.)
> 
> Note that the order of operations is different than what I've mentioned 
> before with non-saturated conversion (downscale if needed, resize, upscale if 
> needed), but it works because we only do the upscale as a resize+upscale. 
> Somewhere in here you also need to change the signedness of the value, but 
> I'm not entirely certain where. Likely after 4.
> 
> Everything I've mentioned here is semi-conjectural, since our implementation 
> has different type widths than the defaults in this one, we can only saturate 
> on _Fract, and our unsigned types have padding. It's possible that there are 
> some assumptions that cause this method to fail for unsigned without padding, 
> or perhaps for some other type conversion, but I haven't come up with a 
> counterexample yet.
Now that I think about it a bit more, it's clear that the Saturate routine does 
not work for unsigned fixed-point without padding. That would need to be taken 
into consideration, but the rest should work.


Repository:
  rC Clang

https://reviews.llvm.org/D48661



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to