| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- class BackwardPass
- {
- template <typename T>
- friend class TempTracker;
- friend class NumberTemp;
- friend class ObjectTemp;
- #if DBG
- friend class ObjectTempVerify;
- #endif
- public:
- BackwardPass(Func * func, GlobOpt * globOpt, Js::Phase tag);
- void Optimize();
- static bool DoDeadStore(Func* func, StackSym* sym);
- private:
- void CleanupBackwardPassInfoInFlowGraph();
- void OptBlock(BasicBlock * block);
- void MergeSuccBlocksInfo(BasicBlock * block);
- void ProcessLoopCollectionPass(BasicBlock *const lastBlock);
- void ProcessLoop(BasicBlock * lastBlock);
- void ProcessBlock(BasicBlock * block);
- bool IsFormalParamSym(Func * func, Sym * sym) const;
- bool CanDeadStoreInstrForScopeObjRemoval(Sym *sym = nullptr) const;
- void TraceDeadStoreOfInstrsForScopeObjectRemoval();
- IR::Instr * TryChangeInstrForStackArgOpt();
- void InsertArgInsForFormals();
- void ProcessBailOnStackArgsOutOfActualsRange();
- void MarkScopeObjSymUseForStackArgOpt();
- bool DeadStoreOrChangeInstrForScopeObjRemoval(IR::Instr ** pInstrPrev);
- void ProcessUse(IR::Opnd * opnd);
- bool ProcessDef(IR::Opnd * opnd);
- void ProcessTransfers(IR::Instr * instr);
- void ProcessFieldKills(IR::Instr * instr);
- template<typename T> void ClearBucketsOnFieldKill(IR::Instr *instr, HashTable<T> *table);
- void ProcessFieldHoistKills(IR::Instr * instr);
- bool ProcessBailOutInfo(IR::Instr * instr);
- void ProcessBailOutInfo(IR::Instr * instr, BailOutInfo * bailOutInfo);
- void ProcessPendingPreOpBailOutInfo(IR::Instr *const currentInstr);
- void ProcessBailOutArgObj(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed);
- void ProcessBailOutConstants(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed, BVSparse<JitArenaAllocator>* argSymsBv);
- void ProcessBailOutCopyProps(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed, BVSparse<JitArenaAllocator>* argSymsBv);
- bool ProcessStackSymUse(StackSym * sym, BOOLEAN isNonByteCodeUse);
- bool ProcessSymUse(Sym * sym, bool isRegOpndUse, BOOLEAN isNonByteCodeUse);
- bool MayPropertyBeWrittenTo(Js::PropertyId propertyId);
- void ProcessPropertySymOpndUse(IR::PropertySymOpnd *opnd);
- bool ProcessPropertySymUse(PropertySym *propertySym);
- void ProcessNewScObject(IR::Instr* instr);
- void MarkTemp(StackSym * sym);
- bool ProcessInlineeStart(IR::Instr* instr);
- void ProcessInlineeEnd(IR::Instr* instr);
- void MarkTempProcessInstr(IR::Instr * instr);
- void RemoveEmptyLoopAfterMemOp(Loop *loop);
- void RemoveEmptyLoops();
- bool IsEmptyLoopAfterMemOp(Loop *loop);
- void RestoreInductionVariableValuesAfterMemOp(Loop *loop);
- bool DoDeadStoreLdStForMemop(IR::Instr *instr);
- bool DeadStoreInstr(IR::Instr *instr);
- void CollectCloneStrCandidate(IR::Opnd *opnd);
- void InvalidateCloneStrCandidate(IR::Opnd *opnd);
- #if DBG_DUMP
- void DumpBlockData(BasicBlock * block);
- void DumpMarkTemp();
- #endif
- static bool UpdateImplicitCallBailOutKind(IR::Instr *const instr, bool needsBailOutOnImplicitCall);
- bool ProcessNoImplicitCallUses(IR::Instr *const instr);
- void ProcessNoImplicitCallDef(IR::Instr *const instr);
- template<class F> IR::Opnd *FindNoImplicitCallUse(IR::Instr *const instr, StackSym *const sym, const F IsCheckedUse, IR::Instr * *const noImplicitCallUsesInstrRef = nullptr);
- template<class F> IR::Opnd *FindNoImplicitCallUse(IR::Instr *const instr, IR::Opnd *const opnd, const F IsCheckedUse, IR::Instr * *const noImplicitCallUsesInstrRef = nullptr);
- void ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *const arrayRegOpnd);
- void UpdateArrayValueTypes(IR::Instr *const instr, IR::Opnd *opnd);
- void UpdateArrayBailOutKind(IR::Instr *const instr);
- void TrackBitWiseOrNumberOp(IR::Instr *const instr);
- void SetSymIsNotUsedOnlyInBitOps(IR::Opnd *const opnd);
- void SetSymIsUsedOnlyInBitOpsIfLastUse(IR::Opnd *const opnd);
- void SetSymIsNotUsedOnlyInNumber(IR::Opnd *const opnd);
- void SetSymIsUsedOnlyInNumberIfLastUse(IR::Opnd *const opnd);
- void TrackIntUsage(IR::Instr *const instr);
- void RemoveNegativeZeroBailout(IR::Instr* instr);
- void SetNegativeZeroDoesNotMatterIfLastUse(IR::Opnd *const opnd);
- void SetNegativeZeroMatters(IR::Opnd *const opnd);
- void SetCouldRemoveNegZeroBailoutForDefIfLastUse(IR::Opnd *const opnd);
- void SetIntOverflowDoesNotMatterIfLastUse(IR::Opnd *const opnd);
- void SetIntOverflowMatters(IR::Opnd *const opnd);
- bool SetIntOverflowDoesNotMatterInRangeIfLastUse(IR::Opnd *const opnd, const int addSubUses);
- bool SetIntOverflowDoesNotMatterInRangeIfLastUse(StackSym *const stackSym, const int addSubUses);
- void SetIntOverflowMattersInRange(IR::Opnd *const opnd);
- void TransferCompoundedAddSubUsesToSrcs(IR::Instr *const instr, const int addSubUses);
- void EndIntOverflowDoesNotMatterRange();
- void TrackFloatSymEquivalence(IR::Instr *const instr);
- void DeadStoreImplicitCallBailOut(IR::Instr * instr, bool hasLiveFields);
- void DeadStoreTypeCheckBailOut(IR::Instr * instr);
- bool IsImplicitCallBailOutCurrentlyNeeded(IR::Instr * instr, bool mayNeedImplicitCallBailOut, bool hasLiveFields);
- bool TrackNoImplicitCallInlinees(IR::Instr *instr);
- bool ProcessBailOnNoProfile(IR::Instr *instr, BasicBlock *block);
- bool DoByteCodeUpwardExposedUsed() const;
- void DoSetDead(IR::Opnd * opnd, bool isDead) const;
- bool DoFieldHoistCandidates() const;
- bool DoFieldHoistCandidates(Loop * loop) const;
- bool DoMarkTempObjects() const;
- bool DoMarkTempNumbers() const;
- bool DoMarkTempNumbersOnTempObjects() const;
- #if DBG
- bool DoMarkTempObjectVerify() const;
- #endif
- static bool DoDeadStore(Func* func);
- bool DoDeadStore() const;
- bool DoDeadStoreSlots() const;
- bool DoTrackNegativeZero() const;
- bool DoTrackBitOpsOrNumber()const;
- bool DoTrackIntOverflow() const;
- bool DoTrackCompoundedIntOverflow() const;
- bool DoTrackNon32BitOverflow() const;
- #if DBG_DUMP
- bool IsTraceEnabled() const;
- #endif
- bool IsCollectionPass() const { return isCollectionPass; }
- bool IsPrePass() const { return this->currentPrePassLoop != nullptr; }
- void DeleteBlockData(BasicBlock * block);
- void TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *block);
- void TrackObjTypeSpecWriteGuards(IR::PropertySymOpnd *opnd, BasicBlock *block);
- void TrackAddPropertyTypes(IR::PropertySymOpnd *opnd, BasicBlock *block);
- void InsertTypeTransition(IR::Instr *instrInsertBefore, int symId, AddPropertyCacheBucket *data);
- void InsertTypeTransition(IR::Instr *instrInsertBefore, StackSym *objSym, AddPropertyCacheBucket *data);
- void InsertTypeTransitionAtBlock(BasicBlock *block, int symId, AddPropertyCacheBucket *data);
- void InsertTypeTransitionsAtPriorSuccessors(BasicBlock *block, BasicBlock *blockSucc, int symId, AddPropertyCacheBucket *data);
- void InsertTypeTransitionAfterInstr(IR::Instr *instr, int symId, AddPropertyCacheBucket *data);
- void InsertTypeTransitionsAtPotentialKills();
- bool TransitionUndoesObjectHeaderInlining(AddPropertyCacheBucket *data) const;
- template<class Fn> void ForEachAddPropertyCacheBucket(Fn fn);
- static ObjTypeGuardBucket MergeGuardedProperties(ObjTypeGuardBucket bucket1, ObjTypeGuardBucket bucket2);
- static ObjWriteGuardBucket MergeWriteGuards(ObjWriteGuardBucket bucket1, ObjWriteGuardBucket bucket2);
- bool ReverseCopyProp(IR::Instr *instr);
- bool FoldCmBool(IR::Instr *instr);
- void SetWriteThroughSymbolsSetForRegion(BasicBlock * catchBlock, Region * tryRegion);
- bool CheckWriteThroughSymInRegion(Region * region, StackSym * sym);
- private:
- // Javascript number values (64-bit floats) have 53 bits excluding the sign bit to precisely represent integers. If we have
- // compounded uses in add/sub, such as:
- // s1 = s0 + s0
- // s2 = s1 + s1
- // s3 = s2 + s2
- // ...
- // And s0 has a 32-bit (signed or unsigned) int value, then we can do 53 - 32 such add/sub operations and guarantee that the
- // final result does not overflow the 53 bits. So long as that is the case, and the final result is only used in operations
- // that convert their srcs to int32s (such as bitwise operations), then overflow checks can be omitted on these adds/subs.
- // Once the result overflows 53 bits, the semantics of converting that imprecisely represented float value to int32 changes
- // and is no longer equivalent to a simple truncate of the precise int value.
- static const int MaxCompoundedUsesInAddSubForIgnoringIntOverflow = 53 - 32;
- Func * const func;
- GlobOpt * globOpt;
- JitArenaAllocator * tempAlloc;
- Js::Phase tag;
- Loop * currentPrePassLoop;
- BasicBlock * currentBlock;
- Region * currentRegion;
- IR::Instr * currentInstr;
- IR::Instr * preOpBailOutInstrToProcess;
- BVSparse<JitArenaAllocator> * negativeZeroDoesNotMatterBySymId;
- BVSparse<JitArenaAllocator> * symUsedOnlyForBitOpsBySymId;
- BVSparse<JitArenaAllocator> * symUsedOnlyForNumberBySymId;
- BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterBySymId;
- BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterInRangeBySymId;
- BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeInt;
- BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeLossyInt;
- StackSym *considerSymAsRealUseInNoImplicitCallUses;
- bool intOverflowCurrentlyMattersInRange;
- bool isCollectionPass;
- class FloatSymEquivalenceClass
- {
- private:
- BVSparse<JitArenaAllocator> bv;
- bool requiresBailOnNotNumber;
- public:
- FloatSymEquivalenceClass(JitArenaAllocator *const allocator) : bv(allocator), requiresBailOnNotNumber(false)
- {
- }
- BVSparse<JitArenaAllocator> *Bv()
- {
- return &bv;
- }
- bool RequiresBailOnNotNumber() const
- {
- return requiresBailOnNotNumber;
- }
- void Set(const StackSym *const sym)
- {
- bv.Set(sym->m_id);
- if(sym->m_requiresBailOnNotNumber)
- {
- requiresBailOnNotNumber = true;
- }
- }
- void Or(const FloatSymEquivalenceClass *const other)
- {
- bv.Or(&other->bv);
- if(other->requiresBailOnNotNumber)
- {
- requiresBailOnNotNumber = true;
- }
- }
- };
- typedef JsUtil::BaseDictionary<SymID, FloatSymEquivalenceClass *, JitArenaAllocator> FloatSymEquivalenceMap;
- FloatSymEquivalenceMap *floatSymEquivalenceMap;
- // Use by numberTemp to keep track of the property sym that is used to represent a property, since we don't trace aliasing
- typedef JsUtil::BaseDictionary<Js::PropertyId, SymID, JitArenaAllocator> NumberTempRepresentativePropertySymMap;
- NumberTempRepresentativePropertySymMap * numberTempRepresentativePropertySym;
- #if DBG_DUMP
- uint32 numDeadStore;
- uint32 numMarkTempNumber;
- uint32 numMarkTempNumberTransferred;
- uint32 numMarkTempObject;
- #endif
- uint32 implicitCallBailouts;
- uint32 fieldOpts;
- };
|