Skip to content

Commit c794439

Browse files
Jiawei-ShaoDawn LUCI CQ
authored andcommitted
Range Analysis: Compute range of Binary with << operator
This patch computes the range of a `Binary` with `<<` (shift-left) operator when the `lhs` is a non-negative integer. Bug: 348701956 Test: tint_unittests Change-Id: I5e52e5504ba749312edbaef0a6f88c0b40dd3367 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/245775 Reviewed-by: James Price <[email protected]> Commit-Queue: Jiawei Shao <[email protected]>
1 parent 8d6bdd0 commit c794439

File tree

2 files changed

+1216
-0
lines changed

2 files changed

+1216
-0
lines changed

src/tint/lang/core/ir/analysis/integer_range_analysis.cc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ struct IntegerRangeAnalysisImpl {
281281
case BinaryOp::kDivide:
282282
return ComputeAndCacheIntegerRangeForBinaryDivide(binary, range_lhs, range_rhs);
283283

284+
case BinaryOp::kShiftLeft:
285+
return ComputeAndCacheIntegerRangeForBinaryShiftLeft(binary, range_lhs, range_rhs);
286+
284287
default:
285288
return nullptr;
286289
}
@@ -1038,6 +1041,60 @@ struct IntegerRangeAnalysisImpl {
10381041
}
10391042
}
10401043

1044+
const IntegerRangeInfo* ComputeAndCacheIntegerRangeForBinaryShiftLeft(
1045+
const Binary* binary,
1046+
const IntegerRangeInfo* lhs,
1047+
const IntegerRangeInfo* rhs) {
1048+
auto rhs_u32 = std::get<IntegerRangeInfo::UnsignedIntegerRange>(rhs->range);
1049+
1050+
// rhs_u32 must be less than the bit width of i32 and u32 (32):
1051+
// rhs_u32.min_bound <= rhs_u32.max_bound < 32
1052+
if (rhs_u32.max_bound >= 32) {
1053+
return nullptr;
1054+
}
1055+
1056+
if (std::holds_alternative<IntegerRangeInfo::SignedIntegerRange>(lhs->range)) {
1057+
auto lhs_i32 = std::get<IntegerRangeInfo::SignedIntegerRange>(lhs->range);
1058+
1059+
// Currently we require `lhs` must be non-negative.
1060+
// 0 <= lhs.min_bound <= lhs.max_bound
1061+
if (lhs_i32.min_bound < 0) {
1062+
return nullptr;
1063+
}
1064+
1065+
// [min1, max1] << [min2, max2] => [min1 << min2, max1 << max2]
1066+
// `max_bound` (as a uint64_t) won't be overflow because `rhs_u32.max_bound` < 32.
1067+
uint64_t max_bound = static_cast<uint64_t>(lhs_i32.max_bound) << rhs_u32.max_bound;
1068+
1069+
// Overflow an `i32` is not allowed, which means:
1070+
// min_bound <= max_bound <= i32::kHighestValue
1071+
if (max_bound > static_cast<uint64_t>(i32::kHighestValue)) {
1072+
return nullptr;
1073+
}
1074+
1075+
int64_t min_bound = lhs_i32.min_bound << rhs_u32.min_bound;
1076+
auto result = integer_binary_range_info_map_.Add(
1077+
binary, IntegerRangeInfo(min_bound, static_cast<int64_t>(max_bound)));
1078+
return &result.value;
1079+
} else {
1080+
auto lhs_u32 = std::get<IntegerRangeInfo::UnsignedIntegerRange>(lhs->range);
1081+
1082+
// `max_bound` (as a uint64_t) won't be overflow because `rhs_u32.max_bound` < 32.
1083+
uint64_t max_bound = lhs_u32.max_bound << rhs_u32.max_bound;
1084+
1085+
// Overflow a `u32` is not allowed, which means:
1086+
// min_bound <= max_bound <= u32::kHighestValue
1087+
if (max_bound > u32::kHighestValue) {
1088+
return nullptr;
1089+
}
1090+
1091+
uint64_t min_bound = lhs_u32.min_bound << rhs_u32.min_bound;
1092+
auto result =
1093+
integer_binary_range_info_map_.Add(binary, IntegerRangeInfo(min_bound, max_bound));
1094+
return &result.value;
1095+
}
1096+
}
1097+
10411098
Hashmap<const FunctionParam*, Vector<IntegerRangeInfo, 3>, 4>
10421099
integer_function_param_range_info_map_;
10431100
Hashmap<const Var*, IntegerRangeInfo, 8> integer_var_range_info_map_;

0 commit comments

Comments
 (0)