| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- uint8 OpCodeToHash[Js::OpCode::Count];
- static Js::OpCode HashToOpCode[Js::OpCode::Count];
- class CSEInit
- {
- public:
- // Initializer for OpCodeToHash and HashToOpCode maps.
- CSEInit()
- {
- uint8 hash = 1;
- for (Js::OpCode opcode = (Js::OpCode)0; opcode < Js::OpCode::Count; opcode = (Js::OpCode)(opcode + 1))
- {
- if (Js::OpCodeUtil::IsValidOpcode(opcode) && OpCodeAttr::CanCSE(opcode) && !OpCodeAttr::ByteCodeOnly(opcode))
- {
- OpCodeToHash[(int)opcode] = hash;
- HashToOpCode[hash] = opcode;
- hash++;
- AssertMsg(hash != 0, "Too many CSE'able opcodes");
- }
- }
- }
- }CSEInit_Dummy;
- bool
- GlobOpt::GetHash(IR::Instr *instr, Value *src1Val, Value *src2Val, ExprAttributes exprAttributes, ExprHash *pHash)
- {
- Js::OpCode opcode = instr->m_opcode;
- // Candidate?
- if (!OpCodeAttr::CanCSE(opcode) && (opcode != Js::OpCode::StElemI_A && opcode != Js::OpCode::StElemI_A_Strict))
- {
- return false;
- }
- ValueNumber valNum1 = 0;
- ValueNumber valNum2 = 0;
- // Get the value number of src1 and src2
- if (instr->GetSrc1())
- {
- if (!src1Val)
- {
- return false;
- }
- valNum1 = src1Val->GetValueNumber();
- if (instr->GetSrc2())
- {
- if (!src2Val)
- {
- return false;
- }
- valNum2 = src2Val->GetValueNumber();
- }
- }
- if (src1Val)
- {
- valNum1 = src1Val->GetValueNumber();
- if (src2Val)
- {
- valNum2 = src2Val->GetValueNumber();
- }
- }
- switch (opcode)
- {
- case Js::OpCode::Ld_I4:
- case Js::OpCode::Ld_A:
- // Copy-prop should handle these
- return false;
- case Js::OpCode::Add_I4:
- case Js::OpCode::Add_Ptr:
- opcode = Js::OpCode::Add_A;
- break;
- case Js::OpCode::Sub_I4:
- opcode = Js::OpCode::Sub_A;
- break;
- case Js::OpCode::Mul_I4:
- opcode = Js::OpCode::Mul_A;
- break;
- case Js::OpCode::Rem_I4:
- opcode = Js::OpCode::Rem_A;
- break;
- case Js::OpCode::Div_I4:
- opcode = Js::OpCode::Div_A;
- break;
- case Js::OpCode::Neg_I4:
- opcode = Js::OpCode::Neg_A;
- break;
- case Js::OpCode::Not_I4:
- opcode = Js::OpCode::Not_A;
- break;
- case Js::OpCode::And_I4:
- opcode = Js::OpCode::And_A;
- break;
- case Js::OpCode::Or_I4:
- opcode = Js::OpCode::Or_A;
- break;
- case Js::OpCode::Xor_I4:
- opcode = Js::OpCode::Xor_A;
- break;
- case Js::OpCode::Shl_I4:
- opcode = Js::OpCode::Shl_A;
- break;
- case Js::OpCode::Shr_I4:
- opcode = Js::OpCode::Shr_A;
- break;
- case Js::OpCode::ShrU_I4:
- opcode = Js::OpCode::ShrU_A;
- break;
- case Js::OpCode::StElemI_A:
- case Js::OpCode::StElemI_A_Strict:
- // Make the load available as a CSE
- opcode = Js::OpCode::LdElemI_A;
- break;
- case Js::OpCode::CmEq_I4:
- opcode = Js::OpCode::CmEq_A;
- break;
- case Js::OpCode::CmNeq_I4:
- opcode = Js::OpCode::CmNeq_A;
- break;
- case Js::OpCode::CmLt_I4:
- opcode = Js::OpCode::CmLt_A;
- break;
- case Js::OpCode::CmLe_I4:
- opcode = Js::OpCode::CmLe_A;
- break;
- case Js::OpCode::CmGt_I4:
- opcode = Js::OpCode::CmGt_A;
- break;
- case Js::OpCode::CmGe_I4:
- opcode = Js::OpCode::CmGe_A;
- break;
- case Js::OpCode::CmUnLt_I4:
- opcode = Js::OpCode::CmUnLt_A;
- break;
- case Js::OpCode::CmUnLe_I4:
- opcode = Js::OpCode::CmUnLe_A;
- break;
- case Js::OpCode::CmUnGt_I4:
- opcode = Js::OpCode::CmUnGt_A;
- break;
- case Js::OpCode::CmUnGe_I4:
- opcode = Js::OpCode::CmUnGe_A;
- break;
- }
- pHash->Init(opcode, valNum1, valNum2, exprAttributes);
- #if DBG_DUMP
- if (!pHash->IsValid() && Js::Configuration::Global.flags.Trace.IsEnabled(Js::CSEPhase, this->func->GetSourceContextId(), this->func->GetLocalFunctionId()))
- {
- Output::Print(L" >>>> CSE: Value numbers too big to be hashed in function %s!\n", this->func->GetJnFunction()->GetDisplayName());
- }
- #endif
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (!pHash->IsValid() && Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::CSEPhase, this->func->GetSourceContextId(), this->func->GetLocalFunctionId()))
- {
- Output::Print(L" >>>> CSE: Value numbers too big to be hashed in function %s!\n", this->func->GetJnFunction()->GetDisplayName());
- }
- #endif
- return pHash->IsValid();
- }
- void
- GlobOpt::CSEAddInstr(
- BasicBlock *block,
- IR::Instr *instr,
- Value *dstVal,
- Value *src1Val,
- Value *src2Val,
- Value *dstIndirIndexVal,
- Value *src1IndirIndexVal)
- {
- ExprAttributes exprAttributes;
- ExprHash hash;
- if (!this->DoCSE())
- {
- return;
- }
- bool isArray = false;
- switch(instr->m_opcode)
- {
- case Js::OpCode::LdElemI_A:
- case Js::OpCode::LdInt8ArrViewElem:
- case Js::OpCode::LdUInt8ArrViewElem:
- case Js::OpCode::LdInt16ArrViewElem:
- case Js::OpCode::LdUInt16ArrViewElem:
- case Js::OpCode::LdInt32ArrViewElem:
- case Js::OpCode::LdUInt32ArrViewElem:
- case Js::OpCode::LdFloat32ArrViewElem:
- case Js::OpCode::LdFloat64ArrViewElem:
- case Js::OpCode::StElemI_A:
- case Js::OpCode::StElemI_A_Strict:
- {
- // For arrays, hash the value # of the baseOpnd and indexOpnd
- IR::IndirOpnd *arrayOpnd;
- Value *indirIndexVal;
- if (instr->m_opcode == Js::OpCode::StElemI_A || instr->m_opcode == Js::OpCode::StElemI_A_Strict)
- {
- if (!this->CanCSEArrayStore(instr))
- {
- return;
- }
- dstVal = src1Val;
- arrayOpnd = instr->GetDst()->AsIndirOpnd();
- indirIndexVal = dstIndirIndexVal;
- }
- else
- {
- // all the LdElem and Ld*ArrViewElem
- arrayOpnd = instr->GetSrc1()->AsIndirOpnd();
- indirIndexVal = src1IndirIndexVal;
- }
- src1Val = this->FindValue(block->globOptData.symToValueMap, arrayOpnd->GetBaseOpnd()->m_sym);
- if(indirIndexVal)
- {
- src2Val = indirIndexVal;
- }
- else if (arrayOpnd->GetIndexOpnd())
- {
- src2Val = this->FindValue(block->globOptData.symToValueMap, arrayOpnd->GetIndexOpnd()->m_sym);
- }
- else
- {
- return;
- }
- isArray = true;
- // for typed array do not add instructions whose dst are guaranteed to be int or number
- // as we will try to eliminate bound check for these typed arrays
- if (src1Val->GetValueInfo()->IsLikelyOptimizedVirtualTypedArray())
- {
- exprAttributes = DstIsIntOrNumberAttributes(!instr->dstIsAlwaysConvertedToInt32, !instr->dstIsAlwaysConvertedToNumber);
- }
- break;
- }
- case Js::OpCode::Mul_I4:
- // If int32 overflow is ignored, we only add MULs with 53-bit overflow check to expr map
- if (instr->HasBailOutInfo() && (instr->GetBailOutKind() & IR::BailOutOnMulOverflow) &&
- !instr->ShouldCheckFor32BitOverflow() && instr->ignoreOverflowBitCount != 53)
- {
- return;
- }
- // fall-through
- case Js::OpCode::Neg_I4:
- case Js::OpCode::Add_I4:
- case Js::OpCode::Sub_I4:
- case Js::OpCode::Div_I4:
- case Js::OpCode::Rem_I4:
- case Js::OpCode::Add_Ptr:
- case Js::OpCode::ShrU_I4:
- {
- // Can't CSE and Add where overflow doesn't matter (and no bailout) with one where it does matter... Record whether int
- // overflow or negative zero were ignored.
- exprAttributes = IntMathExprAttributes(ignoredIntOverflowForCurrentInstr, ignoredNegativeZeroForCurrentInstr);
- break;
- }
- case Js::OpCode::InlineMathFloor:
- case Js::OpCode::InlineMathCeil:
- case Js::OpCode::InlineMathRound:
- if (!instr->ShouldCheckForNegativeZero())
- {
- return;
- }
- break;
- }
- ValueInfo *valueInfo = NULL;
- if (instr->GetDst())
- {
- if (!dstVal)
- {
- return;
- }
- valueInfo = dstVal->GetValueInfo();
- if(valueInfo->GetSymStore() == NULL &&
- !(isArray && valueInfo->HasIntConstantValue() && valueInfo->IsIntAndLikelyTagged() && instr->GetSrc1()->IsAddrOpnd()))
- {
- return;
- }
- }
- if (!this->GetHash(instr, src1Val, src2Val, exprAttributes, &hash))
- {
- return;
- }
- int32 intConstantValue;
- if(valueInfo && !valueInfo->GetSymStore() && valueInfo->TryGetIntConstantValue(&intConstantValue))
- {
- Assert(isArray);
- Assert(valueInfo->IsIntAndLikelyTagged());
- Assert(instr->GetSrc1()->IsAddrOpnd());
- // We need a sym associated with a value in the expression value table. Hoist the address into a stack sym associated
- // with the int constant value.
- StackSym *const constStackSym = GetOrCreateTaggedIntConstantStackSym(intConstantValue);
- instr->HoistSrc1(Js::OpCode::Ld_A, RegNOREG, constStackSym);
- SetValue(&blockData, dstVal, constStackSym);
- }
- // We have a candidate. Add it to the exprToValueMap.
- Value ** pVal = block->globOptData.exprToValueMap->FindOrInsertNew(hash);
- *pVal = dstVal;
- if (isArray)
- {
- block->globOptData.liveArrayValues->Set(hash);
- }
- if (MayNeedBailOnImplicitCall(instr, src1Val, src2Val))
- {
- this->currentBlock->globOptData.hasCSECandidates = true;
- // Use LiveFields to track is object.valueOf/toString could get overridden.
- IR::Opnd *src1 = instr->GetSrc1();
- if (src1)
- {
- if (src1->IsRegOpnd())
- {
- StackSym *varSym = src1->AsRegOpnd()->m_sym;
- if (varSym->IsTypeSpec())
- {
- varSym = varSym->GetVarEquivSym(this->func);
- }
- block->globOptData.liveFields->Set(varSym->m_id);
- }
- IR::Opnd *src2 = instr->GetSrc2();
- if (src2 && src2->IsRegOpnd())
- {
- StackSym *varSym = src2->AsRegOpnd()->m_sym;
- if (varSym->IsTypeSpec())
- {
- varSym = varSym->GetVarEquivSym(this->func);
- }
- block->globOptData.liveFields->Set(varSym->m_id);
- }
- }
- }
- }
- bool
- GlobOpt::CSEOptimize(BasicBlock *block, IR::Instr * *const instrRef, Value **pSrc1Val, Value **pSrc2Val, Value **pSrc1IndirIndexVal, bool intMathExprOnly)
- {
- Assert(instrRef);
- IR::Instr *&instr = *instrRef;
- Assert(instr);
- if (!this->DoCSE())
- {
- return false;
- }
- Value *src1Val = *pSrc1Val;
- Value *src2Val = *pSrc2Val;
- Value *src1IndirIndexVal = *pSrc1IndirIndexVal;
- bool isArray = false;
- ExprAttributes exprAttributes;
- ExprHash hash;
- // For arrays, hash the value # of the baseOpnd and indexOpnd
- switch(instr->m_opcode)
- {
- case Js::OpCode::LdInt8ArrViewElem:
- case Js::OpCode::LdUInt8ArrViewElem:
- case Js::OpCode::LdInt16ArrViewElem:
- case Js::OpCode::LdUInt16ArrViewElem:
- case Js::OpCode::LdInt32ArrViewElem:
- case Js::OpCode::LdUInt32ArrViewElem:
- case Js::OpCode::LdFloat32ArrViewElem:
- case Js::OpCode::LdFloat64ArrViewElem:
- case Js::OpCode::LdElemI_A:
- {
- if(intMathExprOnly)
- {
- return false;
- }
- IR::IndirOpnd *arrayOpnd = instr->GetSrc1()->AsIndirOpnd();
- src1Val = this->FindValue(block->globOptData.symToValueMap, arrayOpnd->GetBaseOpnd()->m_sym);
- if(src1IndirIndexVal)
- {
- src2Val = src1IndirIndexVal;
- }
- else if (arrayOpnd->GetIndexOpnd())
- {
- src2Val = this->FindValue(block->globOptData.symToValueMap, arrayOpnd->GetIndexOpnd()->m_sym);
- }
- else
- {
- return false;
- }
- // for typed array do not add instructions whose dst are guaranteed to be int or number
- // as we will try to eliminate bound check for these typed arrays
- if (src1Val->GetValueInfo()->IsLikelyOptimizedVirtualTypedArray())
- {
- exprAttributes = DstIsIntOrNumberAttributes(!instr->dstIsAlwaysConvertedToInt32, !instr->dstIsAlwaysConvertedToNumber);
- }
- isArray = true;
- break;
- }
- case Js::OpCode::Neg_A:
- case Js::OpCode::Add_A:
- case Js::OpCode::Sub_A:
- case Js::OpCode::Mul_A:
- case Js::OpCode::Div_A:
- case Js::OpCode::Rem_A:
- case Js::OpCode::ShrU_A:
- // If the previously-computed matching expression ignored int overflow or negative zero, those attributes must match
- // to be able to CSE this expression
- if(intMathExprOnly && !ignoredIntOverflowForCurrentInstr && !ignoredNegativeZeroForCurrentInstr)
- {
- // Already tried CSE with default attributes
- return false;
- }
- exprAttributes = IntMathExprAttributes(ignoredIntOverflowForCurrentInstr, ignoredNegativeZeroForCurrentInstr);
- break;
- default:
- if(intMathExprOnly)
- {
- return false;
- }
- break;
- }
- if (!this->GetHash(instr, src1Val, src2Val, exprAttributes, &hash))
- {
- return false;
- }
- // See if we have a value for that expression
- Value ** pVal = block->globOptData.exprToValueMap->Get(hash);
- if (pVal == NULL)
- {
- return false;
- }
- ValueInfo *valueInfo = NULL;
- Sym *symStore = NULL;
- Value *val = NULL;
- if (instr->GetDst())
- {
- if (*pVal == NULL)
- {
- return false;
- }
- val = *pVal;
- // Make sure the array value is still live. We can't CSE something like:
- // ... = A[i];
- // B[j] = ...;
- // ... = A[i];
- if (isArray && !block->globOptData.liveArrayValues->Test(hash))
- {
- return false;
- }
- // See if the symStore is still valid
- valueInfo = val->GetValueInfo();
- symStore = valueInfo->GetSymStore();
- Value * symStoreVal = NULL;
- int32 intConstantValue;
- if (!symStore && valueInfo->TryGetIntConstantValue(&intConstantValue))
- {
- // Handle:
- // A[i] = 10;
- // ... = A[i];
- if (!isArray)
- {
- return false;
- }
- if (!valueInfo->IsIntAndLikelyTagged())
- {
- return false;
- }
- symStore = GetTaggedIntConstantStackSym(intConstantValue);
- }
- if(!symStore || !symStore->IsStackSym())
- {
- return false;
- }
- symStoreVal = this->FindValue(block->globOptData.symToValueMap, symStore);
- if (!symStoreVal || symStoreVal->GetValueNumber() != val->GetValueNumber())
- {
- return false;
- }
- val = symStoreVal;
- valueInfo = val->GetValueInfo();
- }
- // Make sure srcs still have same values
- if (instr->GetSrc1())
- {
- if (!src1Val)
- {
- return false;
- }
- if (hash.GetSrc1ValueNumber() != src1Val->GetValueNumber())
- {
- return false;
- }
- IR::Opnd *src1 = instr->GetSrc1();
- if (src1->IsSymOpnd() && src1->AsSymOpnd()->IsPropertySymOpnd())
- {
- Assert(instr->m_opcode == Js::OpCode::CheckFixedFld);
- IR::PropertySymOpnd *propOpnd = src1->AsSymOpnd()->AsPropertySymOpnd();
- if (!propOpnd->IsTypeChecked() && !propOpnd->IsRootObjectNonConfigurableFieldLoad())
- {
- // Require m_CachedTypeChecked for 2 reasons:
- // - We may be relying on this instruction to do a type check for a downstream reference.
- // - This instruction may have a different inline cache, and thus need to check a different type,
- // than the upstream check.
- // REVIEW: We could process this differently somehow to get the type check on the next reference.
- return false;
- }
- }
- if (instr->GetSrc2())
- {
- if (!src2Val)
- {
- return false;
- }
- if (hash.GetSrc2ValueNumber() != src2Val->GetValueNumber())
- {
- return false;
- }
- }
- }
- bool needsBailOnImplicitCall = false;
- // Need implicit call bailouts?
- if (this->MayNeedBailOnImplicitCall(instr, src1Val, src2Val))
- {
- needsBailOnImplicitCall = true;
- IR::Opnd *src1 = instr->GetSrc1();
- if (instr->m_opcode != Js::OpCode::StElemI_A && instr->m_opcode != Js::OpCode::StElemI_A_Strict
- && src1 && src1->IsRegOpnd())
- {
- StackSym *sym = src1->AsRegOpnd()->m_sym;
- if (this->IsTypeSpecialized(sym, block) || block->globOptData.liveInt32Syms->Test(sym->m_id))
- {
- IR::Opnd *src2 = instr->GetSrc2();
- if (!src2 || src2->IsImmediateOpnd())
- {
- needsBailOnImplicitCall = false;
- }
- else if (src2->IsRegOpnd())
- {
- StackSym *sym = src2->AsRegOpnd()->m_sym;
- if (this->IsTypeSpecialized(src2->AsRegOpnd()->m_sym, block) || block->globOptData.liveInt32Syms->Test(sym->m_id))
- {
- needsBailOnImplicitCall = false;
- }
- }
- }
- }
- }
- if (needsBailOnImplicitCall)
- {
- IR::Opnd *src1 = instr->GetSrc1();
- if (src1)
- {
- if (src1->IsRegOpnd())
- {
- StackSym *varSym = src1->AsRegOpnd()->m_sym;
- Assert(!varSym->IsTypeSpec());
- if (!block->globOptData.liveFields->Test(varSym->m_id))
- {
- return false;
- }
- IR::Opnd *src2 = instr->GetSrc2();
- if (src2 && src2->IsRegOpnd())
- {
- StackSym *varSym = src2->AsRegOpnd()->m_sym;
- Assert(!varSym->IsTypeSpec());
- if (!block->globOptData.liveFields->Test(varSym->m_id))
- {
- return false;
- }
- }
- }
- }
- }
- // in asmjs we can have a symstore with a different type
- // x = HEAPF32[i >> 2]
- // y = HEAPI32[i >> 2]
- if (instr->GetDst() && (instr->GetDst()->GetType() != symStore->AsStackSym()->GetType()))
- {
- Assert(GetIsAsmJSFunc());
- return false;
- }
- // SIMD_JS
- if (instr->m_opcode == Js::OpCode::ExtendArg_A)
- {
- // we don't want to CSE ExtendArgs, only the operation using them. To do that, we mimic CSE by transferring the symStore valueInfo to the dst.
- IR::Opnd *dst = instr->GetDst();
- Value *dstVal = this->FindValue(symStore);
- this->SetValue(&this->blockData, dstVal, dst);
- dst->AsRegOpnd()->m_sym->CopySymAttrs(symStore->AsStackSym());
- return false;
- }
- //
- // Success, do the CSE rewrite.
- //
- #if DBG_DUMP
- if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::CSEPhase, this->func->GetSourceContextId(), this->func->GetLocalFunctionId()))
- {
- Output::Print(L" --- CSE (%s): ", this->func->GetJnFunction()->GetDisplayName());
- instr->Dump();
- }
- #endif
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::CSEPhase, this->func->GetSourceContextId(), this->func->GetLocalFunctionId()))
- {
- Output::Print(L" --- CSE (%s): %s\n", this->func->GetJnFunction()->GetDisplayName(), Js::OpCodeUtil::GetOpCodeName(instr->m_opcode));
- }
- #endif
- this->CaptureByteCodeSymUses(instr);
- if (!instr->GetDst())
- {
- instr->m_opcode = Js::OpCode::Nop;
- return true;
- }
- AnalysisAssert(valueInfo);
- IR::Opnd *cseOpnd;
- cseOpnd = IR::RegOpnd::New(symStore->AsStackSym(), instr->GetDst()->GetType(), instr->m_func);
- cseOpnd->SetValueType(valueInfo->Type());
- cseOpnd->SetIsJITOptimizedReg(true);
- if (needsBailOnImplicitCall)
- {
- this->CaptureNoImplicitCallUses(cseOpnd, false);
- }
- int32 intConstantValue;
- if (valueInfo->TryGetIntConstantValue(&intConstantValue) && valueInfo->IsIntAndLikelyTagged())
- {
- cseOpnd->Free(func);
- cseOpnd = IR::AddrOpnd::New(Js::TaggedInt::ToVarUnchecked(intConstantValue), IR::AddrOpndKindConstantVar, instr->m_func);
- cseOpnd->SetValueType(valueInfo->Type());
- }
- *pSrc1Val = val;
- {
- // Profiled instructions have data that is interpreted differently based on the op code. Since we're changing the op
- // code and due to other similar potential issues, always create a new instr instead of changing the existing one.
- IR::Instr *const originalInstr = instr;
- instr = IR::Instr::New(Js::OpCode::Ld_A, instr->GetDst(), cseOpnd, instr->m_func);
- originalInstr->TransferDstAttributesTo(instr);
- block->InsertInstrBefore(instr, originalInstr);
- block->RemoveInstr(originalInstr);
- }
- *pSrc2Val = NULL;
- *pSrc1IndirIndexVal = NULL;
- return true;
- }
- void
- GlobOpt::ProcessArrayValueKills(IR::Instr *instr)
- {
- switch (instr->m_opcode)
- {
- case Js::OpCode::StElemI_A:
- case Js::OpCode::StElemI_A_Strict:
- case Js::OpCode::DeleteElemI_A:
- case Js::OpCode::DeleteElemIStrict_A:
- case Js::OpCode::StFld:
- case Js::OpCode::StRootFld:
- case Js::OpCode::StFldStrict:
- case Js::OpCode::StRootFldStrict:
- case Js::OpCode::StSlot:
- case Js::OpCode::StSlotChkUndecl:
- case Js::OpCode::DeleteFld:
- case Js::OpCode::DeleteRootFld:
- case Js::OpCode::DeleteFldStrict:
- case Js::OpCode::DeleteRootFldStrict:
- case Js::OpCode::StInt8ArrViewElem:
- case Js::OpCode::StUInt8ArrViewElem:
- case Js::OpCode::StInt16ArrViewElem:
- case Js::OpCode::StUInt16ArrViewElem:
- case Js::OpCode::StInt32ArrViewElem:
- case Js::OpCode::StUInt32ArrViewElem:
- case Js::OpCode::StFloat32ArrViewElem:
- case Js::OpCode::StFloat64ArrViewElem:
- // These array helpers may change A.length (and A[i] could be A.length)...
- case Js::OpCode::InlineArrayPush:
- case Js::OpCode::InlineArrayPop:
- this->blockData.liveArrayValues->ClearAll();
- break;
- case Js::OpCode::CallDirect:
- Assert(instr->GetSrc1());
- switch(instr->GetSrc1()->AsHelperCallOpnd()->m_fnHelper)
- {
- // These array helpers may change A[i]
- case IR::HelperArray_Reverse:
- case IR::HelperArray_Shift:
- case IR::HelperArray_Unshift:
- case IR::HelperArray_Splice:
- this->blockData.liveArrayValues->ClearAll();
- break;
- }
- break;
- default:
- if (instr->UsesAllFields())
- {
- this->blockData.liveArrayValues->ClearAll();
- }
- break;
- }
- }
- bool
- GlobOpt::NeedBailOnImplicitCallForCSE(BasicBlock *block, bool isForwardPass)
- {
- return isForwardPass && block->globOptData.hasCSECandidates;
- }
- bool
- GlobOpt::DoCSE()
- {
- if (PHASE_OFF(Js::CSEPhase, this->func))
- {
- return false;
- }
- if (this->IsLoopPrePass())
- {
- return false;
- }
- if (PHASE_FORCE(Js::CSEPhase, this->func))
- {
- // Force always turn it on
- return true;
- }
- if (!this->DoFieldOpts(this->currentBlock->loop) && !GetIsAsmJSFunc())
- {
- return false;
- }
- return true;
- }
- bool
- GlobOpt::CanCSEArrayStore(IR::Instr *instr)
- {
- IR::Opnd *arrayOpnd = instr->GetDst();
- Assert(arrayOpnd->IsIndirOpnd());
- IR::RegOpnd *baseOpnd = arrayOpnd->AsIndirOpnd()->GetBaseOpnd();
- ValueType baseValueType(baseOpnd->GetValueType());
- // Only handle definite arrays for now. Typed Arrays would require truncation of the CSE'd value.
- if (!baseValueType.IsArrayOrObjectWithArray())
- {
- return false;
- }
- return true;
- }
- #if DBG_DUMP
- void
- DumpExpr(ExprHash hash)
- {
- Output::Print(L"Opcode: %10s src1Val: %d src2Val: %d\n", Js::OpCodeUtil::GetOpCodeName(HashToOpCode[(int)hash.GetOpcode()]), hash.GetSrc1ValueNumber(), hash.GetSrc2ValueNumber());
- }
- #endif
|