@@ -41,6 +41,37 @@ using std::string;
41
41
using std::vector;
42
42
43
43
namespace {
44
+
45
+ bool can_widen (const Expr &e) {
46
+ // We don't want to widen Xtensa 48-bit integers
47
+ return e.type ().bits () <= 32 ;
48
+ }
49
+
50
+ bool can_widen_all (const std::vector<Expr> &args) {
51
+ for (const auto &e : args) {
52
+ if (!can_widen (e)) {
53
+ return false ;
54
+ }
55
+ }
56
+ return true ;
57
+ }
58
+
59
+ Expr widen (Expr a) {
60
+ internal_assert (can_widen (a));
61
+ Type result_type = a.type ().widen ();
62
+ return Cast::make (result_type, std::move (a));
63
+ }
64
+
65
+ Expr narrow (Expr a) {
66
+ Type result_type = a.type ().narrow ();
67
+ return Cast::make (result_type, std::move (a));
68
+ }
69
+
70
+ Expr saturating_narrow (const Expr &a) {
71
+ Type narrow = a.type ().narrow ();
72
+ return saturating_cast (narrow, a);
73
+ }
74
+
44
75
int static_sign (const Expr &x) {
45
76
if (is_positive_const (x)) {
46
77
return 1 ;
@@ -56,6 +87,7 @@ int static_sign(const Expr &x) {
56
87
}
57
88
return 0 ;
58
89
}
90
+
59
91
} // anonymous namespace
60
92
61
93
const FuncValueBounds &empty_func_value_bounds () {
@@ -1195,6 +1227,15 @@ class Bounds : public IRVisitor {
1195
1227
// else fall thru and continue
1196
1228
}
1197
1229
1230
+ const auto handle_expr_bounds = [this , t](const Expr &e) -> void {
1231
+ if (e.defined ()) {
1232
+ e.accept (this );
1233
+ } else {
1234
+ // Just use the bounds of the type
1235
+ this ->bounds_of_type (t);
1236
+ }
1237
+ };
1238
+
1198
1239
if (op->is_intrinsic (Call::abs )) {
1199
1240
Interval a = arg_bounds.get (0 );
1200
1241
interval.min = make_zero (t);
@@ -1468,6 +1509,7 @@ class Bounds : public IRVisitor {
1468
1509
}
1469
1510
} else if (op->args .size () == 1 &&
1470
1511
(op->is_intrinsic (Call::round ) ||
1512
+ op->is_intrinsic (Call::strict_float) ||
1471
1513
op->name == " ceil_f32" || op->name == " ceil_f64" ||
1472
1514
op->name == " floor_f32" || op->name == " floor_f64" ||
1473
1515
op->name == " exp_f32" || op->name == " exp_f64" ||
@@ -1518,14 +1560,107 @@ class Bounds : public IRVisitor {
1518
1560
}
1519
1561
interval = result;
1520
1562
} else if (op->is_intrinsic (Call::widen_right_add)) {
1521
- Expr add = Add::make (op->args [ 0 ], cast (op-> args [ 0 ]. type (), op-> args [ 1 ]) );
1522
- add. accept ( this );
1523
- } else if (op->is_intrinsic (Call::widen_right_sub)) {
1524
- Expr sub = Sub::make (op-> args [ 0 ], cast (op-> args [ 0 ]. type (), op-> args [ 1 ]) );
1525
- sub. accept ( this );
1563
+ internal_assert (op->args . size () == 2 );
1564
+ Expr e = can_widen (op-> args [ 1 ]) ?
1565
+ lower_widen_right_add (op->args [ 0 ], op-> args [ 1 ]) :
1566
+ Expr ( );
1567
+ handle_expr_bounds (e );
1526
1568
} else if (op->is_intrinsic (Call::widen_right_mul)) {
1527
- Expr mul = Mul::make (op->args [0 ], cast (op->args [0 ].type (), op->args [1 ]));
1528
- mul.accept (this );
1569
+ internal_assert (op->args .size () == 2 );
1570
+ Expr e = can_widen (op->args [1 ]) ?
1571
+ lower_widen_right_mul (op->args [0 ], op->args [1 ]) :
1572
+ Expr ();
1573
+ handle_expr_bounds (e);
1574
+ } else if (op->is_intrinsic (Call::widen_right_sub)) {
1575
+ internal_assert (op->args .size () == 2 );
1576
+ Expr e = can_widen (op->args [1 ]) ?
1577
+ lower_widen_right_sub (op->args [0 ], op->args [1 ]) :
1578
+ Expr ();
1579
+ handle_expr_bounds (e);
1580
+ } else if (op->is_intrinsic (Call::widening_add)) {
1581
+ internal_assert (op->args .size () == 2 );
1582
+ Expr e = can_widen_all (op->args ) ?
1583
+ lower_widening_add (op->args [0 ], op->args [1 ]) :
1584
+ Expr ();
1585
+ handle_expr_bounds (e);
1586
+ } else if (op->is_intrinsic (Call::widening_mul)) {
1587
+ internal_assert (op->args .size () == 2 );
1588
+ Expr e = can_widen_all (op->args ) ?
1589
+ lower_widening_mul (op->args [0 ], op->args [1 ]) :
1590
+ Expr ();
1591
+ handle_expr_bounds (e);
1592
+ } else if (op->is_intrinsic (Call::widening_sub)) {
1593
+ internal_assert (op->args .size () == 2 );
1594
+ Expr e = can_widen_all (op->args ) ?
1595
+ lower_widening_sub (op->args [0 ], op->args [1 ]) :
1596
+ Expr ();
1597
+ handle_expr_bounds (e);
1598
+ } else if (op->is_intrinsic (Call::saturating_add)) {
1599
+ internal_assert (op->args .size () == 2 );
1600
+ Expr e = can_widen_all (op->args ) ?
1601
+ narrow (clamp (widen (op->args [0 ]) + widen (op->args [1 ]), t.min (), t.max ())) :
1602
+ Expr ();
1603
+ handle_expr_bounds (e);
1604
+ } else if (op->is_intrinsic (Call::saturating_sub)) {
1605
+ internal_assert (op->args .size () == 2 );
1606
+ Expr e = can_widen_all (op->args ) ?
1607
+ narrow (clamp (widen (op->args [0 ]) - widen (op->args [1 ]), t.min (), t.max ())) :
1608
+ Expr ();
1609
+ handle_expr_bounds (e);
1610
+ } else if (op->is_intrinsic (Call::widening_shift_left)) {
1611
+ internal_assert (op->args .size () == 2 );
1612
+ Expr e = can_widen (op->args [0 ]) ?
1613
+ lower_widening_shift_left (op->args [0 ], op->args [1 ]) :
1614
+ Expr ();
1615
+ handle_expr_bounds (e);
1616
+ } else if (op->is_intrinsic (Call::widening_shift_right)) {
1617
+ internal_assert (op->args .size () == 2 );
1618
+ Expr e = can_widen (op->args [0 ]) ?
1619
+ lower_widening_shift_right (op->args [0 ], op->args [1 ]) :
1620
+ Expr ();
1621
+ handle_expr_bounds (e);
1622
+ } else if (op->is_intrinsic (Call::rounding_shift_right)) {
1623
+ internal_assert (op->args .size () == 2 );
1624
+ // TODO: uses bitwise ops we may not handle well
1625
+ handle_expr_bounds (lower_rounding_shift_right (op->args [0 ], op->args [1 ]));
1626
+ } else if (op->is_intrinsic (Call::rounding_shift_left)) {
1627
+ internal_assert (op->args .size () == 2 );
1628
+ // TODO: uses bitwise ops we may not handle well
1629
+ handle_expr_bounds (lower_rounding_shift_left (op->args [0 ], op->args [1 ]));
1630
+ } else if (op->is_intrinsic (Call::halving_add)) {
1631
+ internal_assert (op->args .size () == 2 );
1632
+ Expr e = can_widen_all (op->args ) ?
1633
+ narrow ((widen (op->args [0 ]) + widen (op->args [1 ])) / 2 ) :
1634
+ Expr ();
1635
+ handle_expr_bounds (e);
1636
+ } else if (op->is_intrinsic (Call::halving_sub)) {
1637
+ internal_assert (op->args .size () == 2 );
1638
+ Expr e = can_widen_all (op->args ) ?
1639
+ narrow ((widen (op->args [0 ]) - widen (op->args [1 ])) / 2 ) :
1640
+ Expr ();
1641
+ handle_expr_bounds (e);
1642
+ } else if (op->is_intrinsic (Call::rounding_halving_add)) {
1643
+ internal_assert (op->args .size () == 2 );
1644
+ Expr e = can_widen_all (op->args ) ?
1645
+ narrow ((widen (op->args [0 ]) + widen (op->args [1 ]) + 1 ) / 2 ) :
1646
+ Expr ();
1647
+ handle_expr_bounds (e);
1648
+ } else if (op->is_intrinsic (Call::rounding_mul_shift_right)) {
1649
+ internal_assert (op->args .size () == 3 );
1650
+ Expr e = can_widen_all (op->args ) ?
1651
+ saturating_narrow (rounding_shift_right (widening_mul (op->args [0 ], op->args [1 ]), op->args [2 ])) :
1652
+ Expr ();
1653
+ handle_expr_bounds (e);
1654
+ } else if (op->is_intrinsic (Call::mul_shift_right)) {
1655
+ internal_assert (op->args .size () == 3 );
1656
+ Expr e = can_widen_all (op->args ) ?
1657
+ saturating_narrow (widening_mul (op->args [0 ], op->args [1 ]) >> op->args [2 ]) :
1658
+ Expr ();
1659
+ handle_expr_bounds (e);
1660
+ } else if (op->is_intrinsic (Call::sorted_avg)) {
1661
+ internal_assert (op->args .size () == 2 );
1662
+ Expr e = lower_sorted_avg (op->args [0 ], op->args [1 ]);
1663
+ handle_expr_bounds (e);
1529
1664
} else if (op->call_type == Call::Halide) {
1530
1665
bounds_of_func (op->name , op->value_index , op->type );
1531
1666
} else {
0 commit comments