@@ -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