已合并
Range Analysis of MUL and MOD #4561
AtomGit-Bot创建于 2023年8月1日
Range Analysis of MUL and MOD #4561
已合并
AtomGit-Bot创建于 2023年8月1日
refs/pull/4561/head合入到master
9 个文件变更+159-15
Mecmascript/compiler/number_gate_info.h+77-2
@@ -102,9 +102,10 @@ public:
102 102 
103 static constexpr int32_t UINT30_MAX = 0x3fffffff;103 static constexpr int32_t UINT30_MAX = 0x3fffffff;
104 static constexpr int32_t TYPED_ARRAY_ONHEAP_MAX = JSTypedArray::MAX_ONHEAP_LENGTH;104 static constexpr int32_t TYPED_ARRAY_ONHEAP_MAX = JSTypedArray::MAX_ONHEAP_LENGTH;
105- static const inline std::vector<int32_t> rangeBounds_ = { INT32_MIN, INT32_MIN + 1,105+ static constexpr int32_t UINT18_MAX = (1 << 18) - 1;
106+ static const inline std::vector<int32_t> rangeBounds_ = { INT32_MIN, INT32_MIN + 1, -UINT18_MAX, -TYPED_ARRAY_ONHEAP_MAX,
106 -1, 0, 1, TYPED_ARRAY_ONHEAP_MAX - 1, TYPED_ARRAY_ONHEAP_MAX, TYPED_ARRAY_ONHEAP_MAX + 1,107 -1, 0, 1, TYPED_ARRAY_ONHEAP_MAX - 1, TYPED_ARRAY_ONHEAP_MAX, TYPED_ARRAY_ONHEAP_MAX + 1,
K0u1hw
K0u1hwK0u1hw2023年8月2日

TYPED_ARRAY_ONHEAP_MAX << 6换个名字

likedislike
107- TYPED_ARRAY_ONHEAP_MAX * 3, UINT30_MAX, UINT30_MAX + 1, INT32_MAX - 1, INT32_MAX };108+ TYPED_ARRAY_ONHEAP_MAX * 3, UINT18_MAX, UINT30_MAX, UINT30_MAX + 1, INT32_MAX - 1, INT32_MAX };
108 109 
109 static RangeInfo NONE()110 static RangeInfo NONE()
110 {111 {
@@ -153,11 +154,81 @@ public:
153 154 
154 RangeInfo operator+ (const RangeInfo &rhs) const155 RangeInfo operator+ (const RangeInfo &rhs) const
155 {156 {
157+ ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_);
156 int32_t nmax = MaybeAddOverflow(rhs) ? INT32_MAX : max_ + rhs.max_;158 int32_t nmax = MaybeAddOverflow(rhs) ? INT32_MAX : max_ + rhs.max_;
157 int32_t nmin = MaybeAddUnderflow(rhs) ? INT32_MIN : min_ + rhs.min_;159 int32_t nmin = MaybeAddUnderflow(rhs) ? INT32_MIN : min_ + rhs.min_;
158 return RangeInfo(nmin, nmax);160 return RangeInfo(nmin, nmax);
159 }161 }
160 162 
163+ RangeInfo operator% (const RangeInfo &rhs) const
164+ {
165+ ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_);
166+ RangeInfo result = RangeInfo(0, 0);
167+ int32_t nmax = std::max(std::abs(rhs.min_), std::abs(rhs.max_));
168+ if (max_ > 0) result = result.Union(RangeInfo(0, nmax - 1));
169+ if (min_ < 0) result = result.Union(RangeInfo(-nmax + 1, 0));
170+ return result;
171+ }
172+ 
173+ bool MaybeZero() const
174+ {
175+ return min_ <= 0 && max_ >= 0;
176+ }
177+ 
178+ RangeInfo operator* (const RangeInfo &rhs) const
179+ {
180+ ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_);
181+ int32_t nmax = GetMaxMulResult(rhs);
182+ int32_t nmin = GetMinMulResult(rhs);
183+ return RangeInfo(nmin, nmax);
184+ }
185+ 
186+ int32_t GetMaxMulResult(const RangeInfo &rhs) const
187+ {
188+ return std::max({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) });
K0u1hw
K0u1hwK0u1hw2023年8月2日

尝试调用MaybeMulOverflow

likedislike
189+ }
190+ 
191+ int32_t GetMinMulResult(const RangeInfo &rhs) const
192+ {
193+ return std::min({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) });
194+ }
195+ 
196+ int32_t TryMul(int32_t lhs, int32_t rhs) const
197+ {
198+ if (MaybeMulOverflow(lhs, rhs)){
199+ return INT32_MAX;
200+ }
201+ if (MaybeMulUnderflow(lhs, rhs)){
202+ return INT32_MIN;
203+ }
204+ return lhs * rhs;
205+ }
206+ 
207+ bool MaybeMulOverflowOrUnderflow(const RangeInfo &rhs) const
208+ {
209+ return MaybeMulOverflow(rhs) || MaybeMulUnderflow(rhs);
210+ }
211+ 
212+ bool MaybeMulUnderflow(const RangeInfo &rhs) const
213+ {
214+ return MaybeMulUnderflow(min_, rhs.max_) || MaybeMulUnderflow(max_, rhs.min_);
215+ }
216+ 
217+ bool MaybeMulOverflow(const RangeInfo &rhs) const
218+ {
219+ return MaybeMulOverflow(max_, rhs.max_) || MaybeMulOverflow(min_, rhs.min_);
220+ }
221+ 
222+ bool MaybeMulUnderflow(int32_t lhs, int32_t rhs) const
223+ {
224+ return (lhs > 0 && rhs < 0 && rhs < INT32_MIN / lhs) || (lhs < 0 && rhs > 0 && lhs < INT32_MIN / rhs);
225+ }
226+ 
227+ bool MaybeMulOverflow(int32_t lhs, int32_t rhs) const
228+ {
229+ return (lhs > 0 && rhs > 0 && lhs > INT32_MAX / rhs) || (lhs < 0 && rhs < 0 && lhs < INT32_MAX / rhs);
230+ }
231+ 
161 bool MaybeSubOverflow(const RangeInfo &rhs) const232 bool MaybeSubOverflow(const RangeInfo &rhs) const
162 {233 {
163 return (rhs.min_ < 0) && (max_ > INT32_MAX + rhs.min_);234 return (rhs.min_ < 0) && (max_ > INT32_MAX + rhs.min_);
@@ -175,6 +246,7 @@ public:
175 246 
176 RangeInfo operator- (const RangeInfo &rhs) const247 RangeInfo operator- (const RangeInfo &rhs) const
177 {248 {
249+ ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_);
178 int32_t nmax = MaybeSubOverflow(rhs) ? INT32_MAX : max_ - rhs.min_;250 int32_t nmax = MaybeSubOverflow(rhs) ? INT32_MAX : max_ - rhs.min_;
179 int32_t nmin = MaybeSubUnderflow(rhs) ? INT32_MIN : min_ - rhs.max_;251 int32_t nmin = MaybeSubUnderflow(rhs) ? INT32_MIN : min_ - rhs.max_;
180 return RangeInfo(nmin, nmax);252 return RangeInfo(nmin, nmax);
@@ -190,6 +262,8 @@ public:
190 262 
191 RangeInfo SHR(const RangeInfo &rhs) const263 RangeInfo SHR(const RangeInfo &rhs) const
192 {264 {
265+ ASSERT(min_ <= max_);
266+ ASSERT(rhs.max_ == rhs.min_);
193 if (MaybeShrOverflow(rhs)) {267 if (MaybeShrOverflow(rhs)) {
194 // assume no overflow occurs since overflow will lead to deopt268 // assume no overflow occurs since overflow will lead to deopt
195 return RangeInfo(0, std::max(0, GetMax()));269 return RangeInfo(0, std::max(0, GetMax()));
@@ -204,6 +278,7 @@ public:
204 278 
205 RangeInfo ASHR(const RangeInfo &rhs) const279 RangeInfo ASHR(const RangeInfo &rhs) const
206 {280 {
281+ ASSERT(min_ <= max_);
207 ASSERT(rhs.max_ == rhs.min_);282 ASSERT(rhs.max_ == rhs.min_);
208 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits283 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits
209 int32_t nmin = min_ >> shift;284 int32_t nmin = min_ >> shift;
Mecmascript/compiler/number_speculative_lowering.cpp+6-1
@@ -355,7 +355,9 @@ void NumberSpeculativeLowering::VisitNumberMod(GateRef gate)
355 }355 }
356 GateRef result = Circuit::NullGate();356 GateRef result = Circuit::NullGate();
357 if (gateType.IsIntType()) {357 if (gateType.IsIntType()) {
358- builder_.Int32CheckRightIsZero(right);358+ if(GetRange(right).MaybeZero()) {
359+ builder_.Int32CheckRightIsZero(right);
360+ }
359 result = CalculateInts<Op>(left, right);361 result = CalculateInts<Op>(left, right);
360 UpdateRange(result, GetRange(gate));362 UpdateRange(result, GetRange(gate));
361 acc_.SetMachineType(gate, MachineType::I32);363 acc_.SetMachineType(gate, MachineType::I32);
@@ -576,6 +578,9 @@ GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
576 break;578 break;
577 }579 }
578 case TypedBinOp::TYPED_MUL:580 case TypedBinOp::TYPED_MUL:
581+ if(!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) {
582+ return builder_.Int32Mul(left, right);
583+ }
579 res = builder_.MulWithOverflow(left, right);584 res = builder_.MulWithOverflow(left, right);
580 break;585 break;
581 case TypedBinOp::TYPED_MOD: {586 case TypedBinOp::TYPED_MOD: {
Mecmascript/compiler/range_analysis.cpp+16-1
@@ -139,6 +139,12 @@ GateRef RangeAnalysis::VisitTypedBinaryOp(GateRef gate)
139 case TypedBinOp::TYPED_SUB:139 case TypedBinOp::TYPED_SUB:
140 range = GetRangeOfCalculate<TypedBinOp::TYPED_SUB>(gate);140 range = GetRangeOfCalculate<TypedBinOp::TYPED_SUB>(gate);
141 break;141 break;
142+ case TypedBinOp::TYPED_MOD:
143+ range = GetRangeOfCalculate<TypedBinOp::TYPED_MOD>(gate);
144+ break;
145+ case TypedBinOp::TYPED_MUL:
146+ range = GetRangeOfCalculate<TypedBinOp::TYPED_MUL>(gate);
147+ break;
142 case TypedBinOp::TYPED_SHR:148 case TypedBinOp::TYPED_SHR:
143 range = GetRangeOfShift<TypedBinOp::TYPED_SHR>(gate);149 range = GetRangeOfShift<TypedBinOp::TYPED_SHR>(gate);
144 break;150 break;
@@ -181,7 +187,6 @@ GateRef RangeAnalysis::VisitRangeGuard(GateRef gate)
181template<TypedBinOp Op>187template<TypedBinOp Op>
182RangeInfo RangeAnalysis::GetRangeOfCalculate(GateRef gate)188RangeInfo RangeAnalysis::GetRangeOfCalculate(GateRef gate)
183{189{
184- ASSERT((Op == TypedBinOp::TYPED_ADD) || (Op == TypedBinOp::TYPED_SUB));
185 auto left = GetRange(acc_.GetValueIn(gate, 0));190 auto left = GetRange(acc_.GetValueIn(gate, 0));
186 auto right = GetRange(acc_.GetValueIn(gate, 1));191 auto right = GetRange(acc_.GetValueIn(gate, 1));
187 if (left.IsNone() || right.IsNone()) {192 if (left.IsNone() || right.IsNone()) {
@@ -192,6 +197,10 @@ RangeInfo RangeAnalysis::GetRangeOfCalculate(GateRef gate)
192 return left + right;197 return left + right;
193 case TypedBinOp::TYPED_SUB:198 case TypedBinOp::TYPED_SUB:
194 return left - right;199 return left - right;
200+ case TypedBinOp::TYPED_MOD:
201+ return left % right;
202+ case TypedBinOp::TYPED_MUL:
203+ return left * right;
195 default:204 default:
196 return RangeInfo::ANY();205 return RangeInfo::ANY();
197 }206 }
@@ -321,6 +330,12 @@ void RangeAnalysis::PrintRangeInfo() const
321 case TypedBinOp::TYPED_ASHR:330 case TypedBinOp::TYPED_ASHR:
322 log += " ashr";331 log += " ashr";
323 break;332 break;
333+ case TypedBinOp::TYPED_MOD:
334+ log += " mod";
335+ break;
336+ case TypedBinOp::TYPED_MUL:
337+ log += " mul";
338+ break;
324 default:339 default:
325 log += " other";340 log += " other";
326 break;341 break;
Mecmascript/compiler/type_inference/method_type_infer.cpp+30-5
@@ -14,7 +14,6 @@
14 */14 */
15 15 
16#include "ecmascript/compiler/type_inference/method_type_infer.h"16#include "ecmascript/compiler/type_inference/method_type_infer.h"
17- 
18#include "ecmascript/jspandafile/js_pandafile_manager.h"17#include "ecmascript/jspandafile/js_pandafile_manager.h"
19#include "ecmascript/ts_types/ts_type_accessor.h"18#include "ecmascript/ts_types/ts_type_accessor.h"
20#include "ecmascript/ts_types/ts_type_parser.h"19#include "ecmascript/ts_types/ts_type_parser.h"
@@ -206,10 +205,6 @@ bool MethodTypeInfer::Infer(GateRef gate)
206 switch (bytecodeInfo.GetOpcode()) {205 switch (bytecodeInfo.GetOpcode()) {
207 case EcmaOpcode::LDNAN:206 case EcmaOpcode::LDNAN:
208 case EcmaOpcode::LDINFINITY:207 case EcmaOpcode::LDINFINITY:
209- case EcmaOpcode::MOD2_IMM8_V8:
210- case EcmaOpcode::AND2_IMM8_V8:
211- case EcmaOpcode::OR2_IMM8_V8:
212- case EcmaOpcode::XOR2_IMM8_V8:
213 case EcmaOpcode::TONUMBER_IMM8:208 case EcmaOpcode::TONUMBER_IMM8:
214 case EcmaOpcode::NEG_IMM8:209 case EcmaOpcode::NEG_IMM8:
215 case EcmaOpcode::EXP_IMM8_V8:210 case EcmaOpcode::EXP_IMM8_V8:
@@ -219,6 +214,9 @@ bool MethodTypeInfer::Infer(GateRef gate)
219 case EcmaOpcode::ASHR2_IMM8_V8:214 case EcmaOpcode::ASHR2_IMM8_V8:
220 case EcmaOpcode::SHR2_IMM8_V8:215 case EcmaOpcode::SHR2_IMM8_V8:
221 case EcmaOpcode::NOT_IMM8:216 case EcmaOpcode::NOT_IMM8:
217+ case EcmaOpcode::AND2_IMM8_V8:
218+ case EcmaOpcode::OR2_IMM8_V8:
219+ case EcmaOpcode::XOR2_IMM8_V8:
222 return SetIntType(gate);220 return SetIntType(gate);
223 case EcmaOpcode::LDBIGINT_ID16:221 case EcmaOpcode::LDBIGINT_ID16:
224 return SetBigIntType(gate);222 return SetBigIntType(gate);
@@ -261,6 +259,8 @@ bool MethodTypeInfer::Infer(GateRef gate)
261 return InferSub2(gate);259 return InferSub2(gate);
262 case EcmaOpcode::MUL2_IMM8_V8:260 case EcmaOpcode::MUL2_IMM8_V8:
263 return InferMul2(gate);261 return InferMul2(gate);
262+ case EcmaOpcode::MOD2_IMM8_V8:
263+ return InferMod2(gate);
264 case EcmaOpcode::DIV2_IMM8_V8:264 case EcmaOpcode::DIV2_IMM8_V8:
265 return InferDiv2(gate);265 return InferDiv2(gate);
266 case EcmaOpcode::INC_IMM8:266 case EcmaOpcode::INC_IMM8:
@@ -553,6 +553,31 @@ bool MethodTypeInfer::InferMul2(GateRef gate)
553 return UpdateType(gate, GateType::NumberType());553 return UpdateType(gate, GateType::NumberType());
554}554}
555 555 
556+/*
557+ * Type Infer rule(satisfy commutative law):
558+ * number % number = number
559+ * int % number = number
560+ * double % number = double
561+ * int % int = int
562+ * int % double = double
563+ * double % double = double
564+ */
565+bool MethodTypeInfer::InferMod2(GateRef gate)
566+{
567+ // 2: number of value inputs
568+ ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
569+ auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
570+ auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
571+ if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
572+ (firInType.IsDoubleType() && secInType.IsNumberType())) {
573+ return UpdateType(gate, GateType::DoubleType());
574+ }
575+ if ((firInType.IsIntType() && secInType.IsIntType())) {
576+ return UpdateType(gate, GateType::IntType());
577+ }
578+ return UpdateType(gate, GateType::NumberType());
579+}
580+ 
556/*581/*
557 * Type Infer rule(satisfy commutative law):582 * Type Infer rule(satisfy commutative law):
558 * in type lowering, both elements will be changed to float64 firstly.583 * in type lowering, both elements will be changed to float64 firstly.
Mecmascript/compiler/type_inference/method_type_infer.h+1-0
@@ -84,6 +84,7 @@ private:
84 bool InferAdd2(GateRef gate);84 bool InferAdd2(GateRef gate);
85 bool InferSub2(GateRef gate);85 bool InferSub2(GateRef gate);
86 bool InferMul2(GateRef gate);86 bool InferMul2(GateRef gate);
87+ bool InferMod2(GateRef gate);
87 bool InferDiv2(GateRef gate);88 bool InferDiv2(GateRef gate);
88 bool InferIncDec(GateRef gate);89 bool InferIncDec(GateRef gate);
89 bool InferToNumberic(GateRef gate);90 bool InferToNumberic(GateRef gate);
Mecmascript/compiler/type_mcr_lowering.cpp+1-1
@@ -34,7 +34,7 @@ void TypeMCRLowering::RunTypeMCRLowering()
34 if (IsLogEnabled()) {34 if (IsLogEnabled()) {
35 LOG_COMPILER(INFO) << "";35 LOG_COMPILER(INFO) << "";
36 LOG_COMPILER(INFO) << "\033[34m" << "=================="36 LOG_COMPILER(INFO) << "\033[34m" << "=================="
37- << " after TypeMCRlowering "37+ << " After TypeMCRlowering "
38 << "[" << GetMethodName() << "] "38 << "[" << GetMethodName() << "] "
39 << "==================" << "\033[0m";39 << "==================" << "\033[0m";
40 circuit_->PrintAllGatesWithBytecode();40 circuit_->PrintAllGatesWithBytecode();
Mtest/aottest/range_guard/range_guard.ts+24-1
@@ -68,6 +68,26 @@ function testcase6() {
68 }68 }
69}69}
70 70 
71+//mod CheckRightIsZero
72+function testcase7() {
73+ const a: number= 20;
74+ let b: number = 5 % a;// not gen CheckRightIsZero
75+ let c: number = 5 % b;// gen CheckRightIsZero
76+}
77+ 
78+//mul_with_overcheck
79+function testcase8(a:number, x:number) {
80+ let z = a >>> 1;
81+ let b: number = z % 10;//range[0, 4095]
82+ 
83+ let c: number = 10 * b;//not gen mul_with_overcheck, range[0,262143]
84+ let d: number = c * b;//not gen mul_with_overcheck, range[0,1073741823]
85+ let e: number = d * c;//gen mul_with_overcheck
86+ 
87+ x = x >>> 1;
88+ let h: number = x * x;//gen mul_with_overcheck
89+}
90+ 
71testcase1(); // 891testcase1(); // 8
72testcase2(); // 892testcase2(); // 8
73 93 
@@ -75,4 +95,7 @@ testcase3();
75testcase4();95testcase4();
76 96 
77testcase5(); 97testcase5();
78-testcase6();98+testcase6();
99+ 
100+testcase7();
101+testcase8(4, 107341001);//deopt
Mtest/typeinfer/bitwise_op/bitwise_op.ts+3-3
@@ -18,13 +18,13 @@ declare function AssertType(value:any, type:string):void;
18 let x:number = 123;18 let x:number = 123;
19 let y:number = 2;19 let y:number = 2;
20 let andRes = x & y;20 let andRes = x & y;
21- AssertType(andRes, "number");21+ AssertType(andRes, "int");
22 22 
23 let orRes = x | y;23 let orRes = x | y;
24- AssertType(orRes, "number");24+ AssertType(orRes, "int");
25 25 
26 let xorRes = x ^ y;26 let xorRes = x ^ y;
27- AssertType(xorRes, "number");27+ AssertType(xorRes, "int");
28 28 
29 let shlRes = x << y;29 let shlRes = x << y;
30 AssertType(shlRes, "int");30 AssertType(shlRes, "int");
Mtest/typeinfer/mod2dyn/mod2dyn.ts+1-1
@@ -18,5 +18,5 @@ declare function AssertType(value:any, type:string):void;
18 let num1 : number = 1;18 let num1 : number = 1;
19 let num2 : number = 2;19 let num2 : number = 2;
20 let ans = num1 % num2;20 let ans = num1 % num2;
21- AssertType(ans, "number");21+ AssertType(ans, "int");
22}22}