@@ -422,15 +422,69 @@ static bool is_valid_range(enum num_t t, struct range x)
422422 }
423423}
424424
425- static struct range range_improve (enum num_t t , struct range old , struct range new )
425+ static struct range range_intersection (enum num_t t , struct range old , struct range new )
426426{
427427 return range (t , max_t (t , old .a , new .a ), min_t (t , old .b , new .b ));
428428}
429429
430+ /*
431+ * Result is precise when 'x' and 'y' overlap or form a continuous range,
432+ * result is an over-approximation if 'x' and 'y' do not overlap.
433+ */
434+ static struct range range_union (enum num_t t , struct range x , struct range y )
435+ {
436+ if (!is_valid_range (t , x ))
437+ return y ;
438+ if (!is_valid_range (t , y ))
439+ return x ;
440+ return range (t , min_t (t , x .a , y .a ), max_t (t , x .b , y .b ));
441+ }
442+
443+ /*
444+ * This function attempts to improve x range intersecting it with y.
445+ * range_cast(... to_t ...) looses precision for ranges that pass to_t
446+ * min/max boundaries. To avoid such precision loses this function
447+ * splits both x and y into halves corresponding to non-overflowing
448+ * sub-ranges: [0, smin] and [smax, -1].
449+ * Final result is computed as follows:
450+ *
451+ * ((x ∩ [0, smax]) ∩ (y ∩ [0, smax])) ∪
452+ * ((x ∩ [smin,-1]) ∩ (y ∩ [smin,-1]))
453+ *
454+ * Precision might still be lost if final union is not a continuous range.
455+ */
456+ static struct range range_refine_in_halves (enum num_t x_t , struct range x ,
457+ enum num_t y_t , struct range y )
458+ {
459+ struct range x_pos , x_neg , y_pos , y_neg , r_pos , r_neg ;
460+ u64 smax , smin , neg_one ;
461+
462+ if (t_is_32 (x_t )) {
463+ smax = (u64 )(u32 )S32_MAX ;
464+ smin = (u64 )(u32 )S32_MIN ;
465+ neg_one = (u64 )(u32 )(s32 )(-1 );
466+ } else {
467+ smax = (u64 )S64_MAX ;
468+ smin = (u64 )S64_MIN ;
469+ neg_one = U64_MAX ;
470+ }
471+ x_pos = range_intersection (x_t , x , range (x_t , 0 , smax ));
472+ x_neg = range_intersection (x_t , x , range (x_t , smin , neg_one ));
473+ y_pos = range_intersection (y_t , y , range (x_t , 0 , smax ));
474+ y_neg = range_intersection (y_t , y , range (y_t , smin , neg_one ));
475+ r_pos = range_intersection (x_t , x_pos , range_cast (y_t , x_t , y_pos ));
476+ r_neg = range_intersection (x_t , x_neg , range_cast (y_t , x_t , y_neg ));
477+ return range_union (x_t , r_pos , r_neg );
478+
479+ }
480+
430481static struct range range_refine (enum num_t x_t , struct range x , enum num_t y_t , struct range y )
431482{
432483 struct range y_cast ;
433484
485+ if (t_is_32 (x_t ) == t_is_32 (y_t ))
486+ x = range_refine_in_halves (x_t , x , y_t , y );
487+
434488 y_cast = range_cast (y_t , x_t , y );
435489
436490 /* If we know that
@@ -444,7 +498,7 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t,
444498 */
445499 if (x_t == S64 && y_t == S32 && y_cast .a <= S32_MAX && y_cast .b <= S32_MAX &&
446500 (s64 )x .a >= S32_MIN && (s64 )x .b <= S32_MAX )
447- return range_improve (x_t , x , y_cast );
501+ return range_intersection (x_t , x , y_cast );
448502
449503 /* the case when new range knowledge, *y*, is a 32-bit subregister
450504 * range, while previous range knowledge, *x*, is a full register
@@ -462,25 +516,11 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t,
462516 x_swap = range (x_t , swap_low32 (x .a , y_cast .a ), swap_low32 (x .b , y_cast .b ));
463517 if (!is_valid_range (x_t , x_swap ))
464518 return x ;
465- return range_improve (x_t , x , x_swap );
466- }
467-
468- if (!t_is_32 (x_t ) && !t_is_32 (y_t ) && x_t != y_t ) {
469- if (x_t == S64 && x .a > x .b ) {
470- if (x .b < y .a && x .a <= y .b )
471- return range (x_t , x .a , y .b );
472- if (x .a > y .b && x .b >= y .a )
473- return range (x_t , y .a , x .b );
474- } else if (x_t == U64 && y .a > y .b ) {
475- if (y .b < x .a && y .a <= x .b )
476- return range (x_t , y .a , x .b );
477- if (y .a > x .b && y .b >= x .a )
478- return range (x_t , x .a , y .b );
479- }
519+ return range_intersection (x_t , x , x_swap );
480520 }
481521
482522 /* otherwise, plain range cast and intersection works */
483- return range_improve (x_t , x , y_cast );
523+ return range_intersection (x_t , x , y_cast );
484524}
485525
486526/* =======================
0 commit comments