@@ -250,6 +250,9 @@ GlobOpt::GlobOpt(Func * func)
250250 doBoundCheckHoist &&
251251 !PHASE_OFF(Js::Phase::LoopCountBasedBoundCheckHoistPhase, func) &&
252252 !func->GetProfileInfo()->IsLoopCountBasedBoundCheckHoistDisabled(func->IsLoopBody())),
253+ doPowIntIntTypeSpec(
254+ doAggressiveIntTypeSpec &&
255+ !func->GetProfileInfo()->IsPowIntIntTypeSpecDisabled()),
253256 isAsmJSFunc(func->m_workItem->GetFunctionBody()->GetIsAsmjsMode())
254257{
255258}
@@ -971,6 +974,7 @@ GlobOpt::MergePredBlocksValueMaps(BasicBlock *block)
971974 BVSparse<JitArenaAllocator> symsRequiringCompensation(tempAlloc);
972975 {
973976 BVSparse<JitArenaAllocator> symsCreatedForMerge(tempAlloc);
977+ bool forceTypeSpecOnLoopHeader = true;
974978 FOREACH_PREDECESSOR_BLOCK(pred, block)
975979 {
976980 if (pred->globOptData.callSequence && pred->globOptData.callSequence->Empty())
@@ -1019,7 +1023,9 @@ GlobOpt::MergePredBlocksValueMaps(BasicBlock *block)
10191023 block,
10201024 pred,
10211025 isLoopPrePass ? nullptr : &symsRequiringCompensation,
1022- isLoopPrePass ? nullptr : &symsCreatedForMerge);
1026+ isLoopPrePass ? nullptr : &symsCreatedForMerge,
1027+ forceTypeSpecOnLoopHeader);
1028+ forceTypeSpecOnLoopHeader = false; // can force type-spec on the loop header only for the first back edge.
10231029 }
10241030
10251031 // Restore the value for the next edge
@@ -1809,7 +1815,8 @@ GlobOpt::MergeBlockData(
18091815 BasicBlock *toBlock,
18101816 BasicBlock *fromBlock,
18111817 BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
1812- BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
1818+ BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
1819+ bool forceTypeSpecOnLoopHeader)
18131820{
18141821 GlobOptBlockData *fromData = &(fromBlock->globOptData);
18151822
@@ -1881,7 +1888,7 @@ GlobOpt::MergeBlockData(
18811888 BVSparse<JitArenaAllocator> tempBv1(this->tempAlloc);
18821889 BVSparse<JitArenaAllocator> tempBv2(this->tempAlloc);
18831890
1884- if (isLoopBackEdge)
1891+ if (isLoopBackEdge && forceTypeSpecOnLoopHeader )
18851892 {
18861893 Loop *const loop = toBlock->loop;
18871894
@@ -4134,6 +4141,24 @@ GlobOpt::IsAllowedForMemOpt(IR::Instr* instr, bool isMemset, IR::RegOpnd *baseOp
41344141 return false;
41354142 }
41364143
4144+ // The following is conservative and works around a bug in induction variable analysis.
4145+ if (baseOpnd->IsArrayRegOpnd())
4146+ {
4147+ IR::ArrayRegOpnd *baseArrayOp = baseOpnd->AsArrayRegOpnd();
4148+ bool hasBoundChecksRemoved = (
4149+ baseArrayOp->EliminatedLowerBoundCheck() &&
4150+ baseArrayOp->EliminatedUpperBoundCheck() &&
4151+ !instr->extractedUpperBoundCheckWithoutHoisting &&
4152+ !instr->loadedArrayHeadSegment &&
4153+ !instr->loadedArrayHeadSegmentLength
4154+ );
4155+ if (!hasBoundChecksRemoved)
4156+ {
4157+ TRACE_MEMOP_VERBOSE(loop, instr, L"Missing bounds check optimization");
4158+ return false;
4159+ }
4160+ }
4161+
41374162 if (!baseValueType.IsTypedArray())
41384163 {
41394164 // Check if the instr can kill the value type of the array
@@ -8970,6 +8995,11 @@ GlobOpt::OptConstFoldUnary(
89708995 case Js::OpCode::Ld_A:
89718996 if (instr->HasBailOutInfo())
89728997 {
8998+ //The profile data for switch expr can be string and in GlobOpt we realize it is an int.
8999+ if(instr->GetBailOutKind() == IR::BailOutExpectingString)
9000+ {
9001+ throw Js::RejitException(RejitReason::DisableSwitchOptExpectingString);
9002+ }
89739003 Assert(instr->GetBailOutKind() == IR::BailOutExpectingInteger);
89749004 instr->ClearBailOutInfo();
89759005 }
@@ -9549,7 +9579,6 @@ GlobOpt::TypeSpecializeInlineBuiltInBinary(IR::Instr **pInstr, Value *src1Val, V
95499579 switch(instr->m_opcode)
95509580 {
95519581 case Js::OpCode::InlineMathAtan2:
9552- case Js::OpCode::InlineMathPow:
95539582 {
95549583 Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInInlineCandidateId(instr->m_opcode); // From actual instr, not profile based.
95559584 Js::BuiltInFlags builtInFlags = Js::JavascriptLibrary::GetFlagsForBuiltIn(builtInId);
@@ -9567,6 +9596,47 @@ GlobOpt::TypeSpecializeInlineBuiltInBinary(IR::Instr **pInstr, Value *src1Val, V
95679596 break;
95689597 }
95699598
9599+ case Js::OpCode::InlineMathPow:
9600+ {
9601+ #ifndef _M_ARM
9602+ if (src2Val->GetValueInfo()->IsLikelyInt())
9603+ {
9604+ bool lossy = false;
9605+
9606+ this->ToInt32(instr, instr->GetSrc2(), this->currentBlock, src2Val, nullptr, lossy);
9607+
9608+ IR::Opnd* src1 = instr->GetSrc1();
9609+ int32 valueMin, valueMax;
9610+ if (src1Val->GetValueInfo()->IsLikelyInt() &&
9611+ this->DoPowIntIntTypeSpec() &&
9612+ src2Val->GetValueInfo()->GetIntValMinMax(&valueMin, &valueMax, this->DoAggressiveIntTypeSpec()) &&
9613+ valueMin >= 0)
9614+
9615+ {
9616+ this->ToInt32(instr, src1, this->currentBlock, src1Val, nullptr, lossy);
9617+ this->TypeSpecializeIntDst(instr, instr->m_opcode, nullptr, src1Val, src2Val, IR::BailOutInvalid, INT32_MIN, INT32_MAX, pDstVal);
9618+
9619+ if(!this->IsLoopPrePass())
9620+ {
9621+ GenerateBailAtOperation(&instr, IR::BailOutOnPowIntIntOverflow);
9622+ }
9623+ }
9624+ else
9625+ {
9626+ this->ToFloat64(instr, src1, this->currentBlock, src1Val, nullptr, IR::BailOutPrimitiveButString);
9627+ TypeSpecializeFloatDst(instr, nullptr, src1Val, src2Val, pDstVal);
9628+ }
9629+ }
9630+ else
9631+ {
9632+ #endif
9633+ this->TypeSpecializeFloatBinary(instr, src1Val, src2Val, pDstVal);
9634+ #ifndef _M_ARM
9635+ }
9636+ #endif
9637+ break;
9638+ }
9639+
95709640 case Js::OpCode::InlineMathImul:
95719641 {
95729642 Assert(this->DoAggressiveIntTypeSpec());
@@ -10435,7 +10505,8 @@ GlobOpt::TypeSpecializeBinary(IR::Instr **pInstr, Value **pSrc1Val, Value **pSrc
1043510505
1043610506 // Type specialize binary operators to int32
1043710507
10438- bool lossy = true;
10508+ bool src1Lossy = true;
10509+ bool src2Lossy = true;
1043910510 IR::BailOutKind bailOutKind = IR::BailOutInvalid;
1044010511 bool ignoredIntOverflow = this->ignoredIntOverflowForCurrentInstr;
1044110512 bool ignoredNegativeZero = false;
@@ -10719,7 +10790,8 @@ GlobOpt::TypeSpecializeBinary(IR::Instr **pInstr, Value **pSrc1Val, Value **pSrc
1071910790 bailOutKind = IR::BailOutOnDivOfMinInt;
1072010791 }
1072110792
10722- lossy = false; // Detect -0 on the sources
10793+ src1Lossy = false; // Detect -0 on the sources
10794+ src2Lossy = false;
1072310795
1072410796 opcode = Js::OpCode::Div_I4;
1072510797 bailOutKind |= IR::BailOnDivResultNotInt;
@@ -10939,7 +11011,17 @@ GlobOpt::TypeSpecializeBinary(IR::Instr **pInstr, Value **pSrc1Val, Value **pSrc
1093911011
1094011012 // Try to type specialize to int32
1094111013
10942- lossy = false;
11014+ // If one of the values is a float constant with a value that fits in a uint32 but not an int32,
11015+ // and the instruction can ignore int overflow, the source value for the purposes of int specialization
11016+ // would have been changed to an int constant value by ignoring overflow. But, the conversion is still lossy.
11017+ if (!(src1OriginalVal && src1OriginalVal->GetValueInfo()->IsFloatConstant() && src1Val && src1Val->GetValueInfo()->HasIntConstantValue()))
11018+ {
11019+ src1Lossy = false;
11020+ }
11021+ if (!(src2OriginalVal && src2OriginalVal->GetValueInfo()->IsFloatConstant() && src2Val && src2Val->GetValueInfo()->HasIntConstantValue()))
11022+ {
11023+ src2Lossy = false;
11024+ }
1094311025
1094411026 switch(instr->m_opcode)
1094511027 {
@@ -11706,26 +11788,29 @@ GlobOpt::TypeSpecializeBinary(IR::Instr **pInstr, Value **pSrc1Val, Value **pSrc
1170611788 }
1170711789
1170811790 Value *src1ValueToSpecialize = src1Val, *src2ValueToSpecialize = src2Val;
11709- if(lossy)
11791+ // Lossy conversions to int32 must be done based on the original source values. For instance, if one of the values is a
11792+ // float constant with a value that fits in a uint32 but not an int32, and the instruction can ignore int overflow, the
11793+ // source value for the purposes of int specialization would have been changed to an int constant value by ignoring
11794+ // overflow. If we were to specialize the sym using the int constant value, it would be treated as a lossless
11795+ // conversion, but since there may be subsequent uses of the same float constant value that may not ignore overflow,
11796+ // this must be treated as a lossy conversion by specializing the sym using the original float constant value.
11797+ if(src1Lossy)
1171011798 {
11711- // Lossy conversions to int32 must be done based on the original source values. For instance, if one of the values is a
11712- // float constant with a value that fits in a uint32 but not an int32, and the instruction can ignore int overflow, the
11713- // source value for the purposes of int specialization would have been changed to an int constant value by ignoring
11714- // overflow. If we were to specialize the sym using the int constant value, it would be treated as a lossless
11715- // conversion, but since there may be subsequent uses of the same float constant value that may not ignore overflow,
11716- // this must be treated as a lossy conversion by specializing the sym using the original float constant value.
1171711799 src1ValueToSpecialize = src1OriginalVal;
11800+ }
11801+ if (src2Lossy)
11802+ {
1171811803 src2ValueToSpecialize = src2OriginalVal;
1171911804 }
1172011805
1172111806 // Make sure the srcs are specialized
1172211807 src1 = instr->GetSrc1();
11723- this->ToInt32(instr, src1, this->currentBlock, src1ValueToSpecialize, nullptr, lossy );
11808+ this->ToInt32(instr, src1, this->currentBlock, src1ValueToSpecialize, nullptr, src1Lossy );
1172411809
1172511810 if (!skipSrc2)
1172611811 {
1172711812 src2 = instr->GetSrc2();
11728- this->ToInt32(instr, src2, this->currentBlock, src2ValueToSpecialize, nullptr, lossy );
11813+ this->ToInt32(instr, src2, this->currentBlock, src2ValueToSpecialize, nullptr, src2Lossy );
1172911814 }
1173011815
1173111816 if(bailOutKind != IR::BailOutInvalid && !this->IsLoopPrePass())
@@ -19320,6 +19405,12 @@ GlobOpt::DoLoopCountBasedBoundCheckHoist() const
1932019405 return doLoopCountBasedBoundCheckHoist;
1932119406}
1932219407
19408+ bool
19409+ GlobOpt::DoPowIntIntTypeSpec() const
19410+ {
19411+ return doPowIntIntTypeSpec;
19412+ }
19413+
1932319414bool
1932419415GlobOpt::TrackArgumentsObject()
1932519416{
0 commit comments