From 05ba84366e3e0f42ffd515375cda0d2a0ffe37ed Mon Sep 17 00:00:00 2001 From: Andrew Adams Date: Mon, 28 Aug 2023 15:00:53 -0700 Subject: [PATCH] Fix bounds inference for uint -> int casts Fixes #7807 Fixes #7811 --- src/Bounds.cpp | 7 ++++--- test/correctness/bounds_of_abs.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Bounds.cpp b/src/Bounds.cpp index e96217edb2c1..018979f91773 100644 --- a/src/Bounds.cpp +++ b/src/Bounds.cpp @@ -281,9 +281,10 @@ class Bounds : public IRVisitor { bool could_overflow = true; if (to.can_represent(from) || to.is_float()) { could_overflow = false; - } else if (to.is_int() && to.bits() >= 32) { - // If we cast to an int32 or greater, assume that it won't - // overflow. Signed 32-bit integer overflow is undefined. + } else if (from.is_float() && to.is_int() && to.bits() >= 32) { + // If we cast from float to an int32 or greater, assume that it + // won't overflow. Signed 32-bit integer overflow on floating point + // casts is undefined. (Casting from uint is defined to wrap). could_overflow = false; } else if (a.is_bounded()) { if (from.can_represent(to)) { diff --git a/test/correctness/bounds_of_abs.cpp b/test/correctness/bounds_of_abs.cpp index e1fb0da7c783..02567cb7d5bf 100644 --- a/test/correctness/bounds_of_abs.cpp +++ b/test/correctness/bounds_of_abs.cpp @@ -45,6 +45,19 @@ int main(int argc, char **argv) { f5 = lambda(x, input(cast(clamp(abs(1.0f / (x + .1f)), -50, 50)))); check(f5, input, 0, 51); + // Verify that casting the result of abs of a uint32 back to an int32 is + // considered unbounded below - it may produce the most negative int if the + // cast wraps. We won't phrase this like the tests above, because we would + // expect it to fail to compile with an unbounded access error. + Internal::Scope scope; + scope.push(x.name(), Internal::Interval::everything()); + Internal::Interval i = + Internal::bounds_of_expr_in_scope(cast(abs(x)), scope); + if (i.has_lower_bound()) { + printf("Interval should not have had a lower bound\n"); + return 1; + } + printf("Success!\n"); return 0; }