| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- class BasicBlock;
- class FlowEdge;
- class Loop;
- class Region;
- class Func;
- class AddPropertyCacheBucket
- {
- private:
- Js::Type* initialType;
- Js::Type* finalType;
- public:
- AddPropertyCacheBucket() : initialType(nullptr), finalType(nullptr)
- #if DBG
- , deadStoreUnavailableInitialType(nullptr), deadStoreUnavailableFinalType(nullptr)
- #endif
- {
- }
- AddPropertyCacheBucket(const AddPropertyCacheBucket& bucket) :
- initialType(bucket.initialType), finalType(bucket.finalType)
- #if DBG
- , deadStoreUnavailableInitialType(bucket.deadStoreUnavailableInitialType)
- , deadStoreUnavailableFinalType(bucket.deadStoreUnavailableFinalType)
- #endif
- {
- }
- bool operator!=(const AddPropertyCacheBucket& bucket) const
- {
- return this->initialType != bucket.initialType || this->finalType != bucket.finalType;
- }
- bool operator==(const AddPropertyCacheBucket& bucket) const
- {
- return this->initialType == bucket.initialType && this->finalType == bucket.finalType;
- }
- void Copy(AddPropertyCacheBucket *pNew) const
- {
- pNew->initialType = this->initialType;
- pNew->finalType = this->finalType;
- #if DBG
- pNew->deadStoreUnavailableInitialType = this->deadStoreUnavailableInitialType;
- pNew->deadStoreUnavailableFinalType = this->deadStoreUnavailableFinalType;
- #endif
- }
- Js::Type *GetInitialType() const { return this->initialType; }
- Js::Type *GetFinalType() const { return this->finalType; }
- void SetInitialType(Js::Type *type) { this->initialType = type; }
- void SetFinalType(Js::Type *type) { this->finalType = type; }
- #if DBG_DUMP
- void Dump() const;
- #endif
- #ifdef DBG
- Js::Type * deadStoreUnavailableInitialType;
- Js::Type * deadStoreUnavailableFinalType;
- #endif
- };
- class ObjTypeGuardBucket
- {
- private:
- BVSparse<JitArenaAllocator>* guardedPropertyOps;
- bool needsMonoCheck;
- public:
- ObjTypeGuardBucket() : guardedPropertyOps(nullptr), needsMonoCheck(false) {}
- ObjTypeGuardBucket(BVSparse<JitArenaAllocator>* guardedPropertyOps) : needsMonoCheck(false)
- {
- this->guardedPropertyOps = (guardedPropertyOps != nullptr ? guardedPropertyOps->CopyNew() : nullptr);
- }
- void Copy(ObjTypeGuardBucket *pNew) const
- {
- pNew->guardedPropertyOps = this->guardedPropertyOps ? this->guardedPropertyOps->CopyNew() : nullptr;
- pNew->needsMonoCheck = this->needsMonoCheck;
- }
- BVSparse<JitArenaAllocator> *GetGuardedPropertyOps() const { return this->guardedPropertyOps; }
- void SetGuardedPropertyOps(BVSparse<JitArenaAllocator> *guardedPropertyOps) { this->guardedPropertyOps = guardedPropertyOps; }
- void AddToGuardedPropertyOps(uint propertyOpId) { Assert(this->guardedPropertyOps != nullptr); this->guardedPropertyOps->Set(propertyOpId); }
- bool NeedsMonoCheck() const { return this->needsMonoCheck; }
- void SetNeedsMonoCheck(bool value) { this->needsMonoCheck = value; }
- #if DBG_DUMP
- void Dump() const;
- #endif
- };
- class ObjWriteGuardBucket
- {
- private:
- BVSparse<JitArenaAllocator>* writeGuards;
- public:
- ObjWriteGuardBucket() : writeGuards(nullptr) {}
- ObjWriteGuardBucket(BVSparse<JitArenaAllocator>* writeGuards) { this->writeGuards = (writeGuards != nullptr ? writeGuards->CopyNew() : nullptr); }
- void Copy(ObjWriteGuardBucket *pNew) const
- {
- pNew->writeGuards = this->writeGuards ? this->writeGuards->CopyNew() : nullptr;
- }
- BVSparse<JitArenaAllocator> *GetWriteGuards() const { return this->writeGuards; }
- void SetWriteGuards(BVSparse<JitArenaAllocator> *writeGuards) { this->writeGuards = writeGuards; }
- void AddToWriteGuards(uint writeGuardId) { Assert(this->writeGuards != nullptr); this->writeGuards->Set(writeGuardId); }
- #if DBG_DUMP
- void Dump() const;
- #endif
- };
- class FlowGraph
- {
- friend Loop;
- public:
- static FlowGraph * New(Func *func, JitArenaAllocator *alloc);
- FlowGraph(Func *func, JitArenaAllocator *fgAlloc) :
- func(func),
- alloc(fgAlloc),
- blockList(nullptr),
- blockCount(0),
- tailBlock(nullptr),
- loopList(nullptr),
- catchLabelStack(nullptr),
- hasBackwardPassInfo(false),
- hasLoop(false),
- implicitCallFlags(Js::ImplicitCall_HasNoInfo)
- {
- }
- void Build(void);
- void Destroy(void);
- void RunPeeps();
- BasicBlock * AddBlock(IR::Instr * firstInstr, IR::Instr * lastInstr, BasicBlock * nextBlock);
- FlowEdge * AddEdge(BasicBlock * predBlock, BasicBlock * succBlock);
- BasicBlock * InsertCompensationCodeForBlockMove(FlowEdge * edge, // Edge where compensation code needs to be inserted
- bool insertCompensationBlockToLoopList = false,
- bool sinkBlockLoop = false // Loop to which compensation block belongs
- );
- BasicBlock * InsertAirlockBlock(FlowEdge * edge);
- void InsertCompBlockToLoopList(Loop *loop, BasicBlock* compBlock, BasicBlock* targetBlock, bool postTarget);
- void RemoveUnreachableBlocks();
- bool RemoveUnreachableBlock(BasicBlock *block, GlobOpt * globOpt = nullptr);
- IR::Instr * RemoveInstr(IR::Instr *instr, GlobOpt * globOpt);
- void RemoveBlock(BasicBlock *block, GlobOpt * globOpt = nullptr, bool tailDuping = false);
- BasicBlock * SetBlockTargetAndLoopFlag(IR::LabelInstr * labelInstr);
- Func* GetFunc() { return func;};
- static void SafeRemoveInstr(IR::Instr *instr);
- void SortLoopLists();
- FlowEdge * FindEdge(BasicBlock *predBlock, BasicBlock *succBlock);
- #if DBG_DUMP
- void Dump();
- void Dump(bool verbose, const wchar_t *form);
- #endif
- JitArenaAllocator * alloc;
- BasicBlock * blockList;
- BasicBlock * tailBlock;
- Loop * loopList;
- SList<IR::LabelInstr*> * catchLabelStack;
- bool hasBackwardPassInfo;
- bool hasLoop;
- Js::ImplicitCallFlags implicitCallFlags;
- private:
- void FindLoops(void);
- bool CanonicalizeLoops(void);
- void BuildLoop(BasicBlock *headBlock, BasicBlock *tailBlock, Loop *parentLoop = nullptr);
- void WalkLoopBlocks(BasicBlock *block, Loop *loop, JitArenaAllocator *tempAlloc);
- void AddBlockToLoop(BasicBlock *block, Loop *loop);
- void UpdateRegionForBlock(BasicBlock *block, Region **blockToRegion);
- Region * PropagateRegionFromPred(BasicBlock *block, BasicBlock *predBlock, Region *predRegion, IR::Instr * &tryInstr);
- IR::Instr * PeepCm(IR::Instr *instr);
- IR::Instr * PeepTypedCm(IR::Instr *instr);
- void MoveBlocksBefore(BasicBlock *blockStart, BasicBlock *blockEnd, BasicBlock *insertBlock);
- bool UnsignedCmpPeep(IR::Instr *cmpInstr);
- bool IsUnsignedOpnd(IR::Opnd *src, IR::Opnd **pShrSrc1);
- #if DBG
- void VerifyLoopGraph();
- #endif
- private:
- void InsertInlineeOnFLowEdge(IR::BranchInstr *instrBr, IR::Instr *inlineeEndInstr, IR::Instr *instrBytecode, Func* origBrFunc, uint32 origByteCodeOffset, uint32 origBranchSrcSymId);
- private:
- Func * func;
- unsigned int blockCount;
- };
- class BasicBlock
- {
- friend class FlowGraph;
- friend class Loop;
- public:
- static BasicBlock * New(FlowGraph * graph);
- void AddPred(FlowEdge * edge, FlowGraph * graph);
- void AddSucc(FlowEdge * edge, FlowGraph * graph);
- void RemovePred(BasicBlock *block, FlowGraph * graph);
- void RemoveSucc(BasicBlock *block, FlowGraph * graph);
- void RemoveDeadPred(BasicBlock *block, FlowGraph * graph);
- void RemoveDeadSucc(BasicBlock *block, FlowGraph * graph);
- void UnlinkPred(BasicBlock *block);
- void UnlinkSucc(BasicBlock *block);
- void UnlinkInstr(IR::Instr * Instr);
- void RemoveInstr(IR::Instr * instr);
- void InsertInstrBefore(IR::Instr *newInstr, IR::Instr *beforeThisInstr);
- void InsertInstrAfter(IR::Instr *newInstr, IR::Instr *afterThisInstr);
- void InsertAfter(IR::Instr * newInstr);
- void InvertBranch(IR::BranchInstr *branch);
- IR::Instr * GetFirstInstr(void) const
- {
- return firstInstr;
- }
- void SetFirstInstr(IR::Instr * instr)
- {
- firstInstr = instr;
- }
- IR::Instr * GetLastInstr(void)
- {
- BasicBlock *blNext = this->next;
- if (blNext)
- {
- return blNext->firstInstr->m_prev;
- }
- else
- {
- return this->func->m_exitInstr;
- }
- }
- void SetLastInstr(IR::Instr * instr)
- {
- // Intentionally empty
- }
- SListBaseCounted<FlowEdge *> * GetPredList(void)
- {
- return &predList;
- }
- SListBaseCounted<FlowEdge *> * GetSuccList(void)
- {
- return &succList;
- }
- SListBaseCounted<FlowEdge *> * GetDeadPredList(void)
- {
- return &deadPredList;
- }
- SListBaseCounted<FlowEdge *> * GetDeadSuccList(void)
- {
- return &deadSuccList;
- }
- unsigned int GetBlockNum(void) const
- {
- return number;
- }
- void SetBlockNum(unsigned int num)
- {
- number = num;
- }
- BasicBlock * GetPrev()
- {
- BasicBlock *block = this;
- do {
- block = block->prev;
- } while (block->isDeleted);
- return block;
- }
- BasicBlock * GetNext()
- {
- BasicBlock *block = this;
- do {
- block = block->next;
- } while (block && block->isDeleted);
- return block;
- }
- uint IncrementDataUseCount()
- {
- return ++this->dataUseCount;
- }
- uint DecrementDataUseCount()
- {
- Assert(this->dataUseCount != 0);
- return --this->dataUseCount;
- }
- uint GetDataUseCount()
- {
- return this->dataUseCount;
- }
- void SetDataUseCount(uint count)
- {
- this->dataUseCount = count;
- }
- bool IsLandingPad();
- #if DBG_DUMP
- void DumpHeader(bool insertCR = true);
- void Dump();
- #endif
- public:
- BasicBlock * next;
- BasicBlock * prev;
- Loop * loop;
- uint8 isDeleted:1;
- uint8 isDead:1;
- uint8 isLoopHeader:1;
- uint8 hasCall:1;
- uint8 isVisited:1;
- uint8 isAirLockCompensationBlock:1;
- #ifdef DBG
- uint8 isBreakBlock:1;
- uint8 isAirLockBlock:1;
- uint8 isBreakCompensationBlockAtSink:1;
- uint8 isBreakCompensationBlockAtSource:1;
- #endif
- // Deadstore data
- BVSparse<JitArenaAllocator> * upwardExposedUses;
- BVSparse<JitArenaAllocator> * upwardExposedFields;
- BVSparse<JitArenaAllocator> * typesNeedingKnownObjectLayout;
- BVSparse<JitArenaAllocator> * fieldHoistCandidates;
- BVSparse<JitArenaAllocator> * slotDeadStoreCandidates;
- TempNumberTracker * tempNumberTracker;
- TempObjectTracker * tempObjectTracker;
- #if DBG
- TempObjectVerifyTracker * tempObjectVerifyTracker;
- #endif
- HashTable<AddPropertyCacheBucket> * stackSymToFinalType;
- HashTable<ObjTypeGuardBucket> * stackSymToGuardedProperties; // Dead store pass only
- HashTable<ObjWriteGuardBucket> * stackSymToWriteGuardsMap; // Backward pass only
- BVSparse<JitArenaAllocator> * noImplicitCallUses;
- BVSparse<JitArenaAllocator> * noImplicitCallNoMissingValuesUses;
- BVSparse<JitArenaAllocator> * noImplicitCallNativeArrayUses;
- BVSparse<JitArenaAllocator> * noImplicitCallJsArrayHeadSegmentSymUses;
- BVSparse<JitArenaAllocator> * noImplicitCallArrayLengthSymUses;
- BVSparse<JitArenaAllocator> * cloneStrCandidates;
- Loop * backwardPassCurrentLoop;
- // Global optimizer data
- GlobOptBlockData globOptData;
- // Bailout data
- BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed;
- #if DBG
- StackSym ** byteCodeRestoreSyms;
- #endif
- IntOverflowDoesNotMatterRange * intOverflowDoesNotMatterRange;
- private:
- BasicBlock(JitArenaAllocator * alloc, Func *func) :
- next(nullptr),
- prev(nullptr),
- firstInstr(nullptr),
- number(k_InvalidNum),
- loop(nullptr),
- isDeleted(false),
- isDead(false),
- isLoopHeader(false),
- hasCall(false),
- upwardExposedUses(nullptr),
- upwardExposedFields(nullptr),
- typesNeedingKnownObjectLayout(nullptr),
- slotDeadStoreCandidates(nullptr),
- tempNumberTracker(nullptr),
- tempObjectTracker(nullptr),
- #if DBG
- tempObjectVerifyTracker(nullptr),
- #endif
- stackSymToFinalType(nullptr),
- stackSymToGuardedProperties(nullptr),
- stackSymToWriteGuardsMap(nullptr),
- noImplicitCallUses(nullptr),
- noImplicitCallNoMissingValuesUses(nullptr),
- noImplicitCallNativeArrayUses(nullptr),
- noImplicitCallJsArrayHeadSegmentSymUses(nullptr),
- noImplicitCallArrayLengthSymUses(nullptr),
- cloneStrCandidates(nullptr),
- byteCodeUpwardExposedUsed(nullptr),
- isAirLockCompensationBlock(false),
- #if DBG
- byteCodeRestoreSyms(nullptr),
- isBreakBlock(false),
- isAirLockBlock(false),
- isBreakCompensationBlockAtSource(false),
- isBreakCompensationBlockAtSink(false),
- #endif
- fieldHoistCandidates(nullptr),
- dataUseCount(0),
- intOverflowDoesNotMatterRange(nullptr),
- func(func),
- globOptData(func)
- {
- }
- void RemovePred(BasicBlock *block, FlowGraph * graph, bool doCleanSucc, bool moveToDead = false);
- void RemoveSucc(BasicBlock *block, FlowGraph * graph, bool doCleanPred, bool moveToDead = false);
- void UnlinkPred(BasicBlock *block, bool doCleanSucc);
- void UnlinkSucc(BasicBlock *block, bool doCleanPred);
- #if DBG_DUMP
- bool Contains(IR::Instr * instr);
- #endif
- private:
- IR::Instr * firstInstr;
- SListBaseCounted<FlowEdge *> predList;
- SListBaseCounted<FlowEdge *> succList;
- SListBaseCounted<FlowEdge *> deadPredList;
- SListBaseCounted<FlowEdge *> deadSuccList;
- Func * func;
- unsigned int number;
- uint dataUseCount;
- static const unsigned int k_InvalidNum = (unsigned)-1;
- };
- class FlowEdge
- {
- public:
- static FlowEdge * New(FlowGraph * graph);
- FlowEdge() :
- predBlock(nullptr),
- succBlock(nullptr),
- pathDependentInfo(nullptr)
- {
- }
- BasicBlock * GetPred(void) const
- {
- return predBlock;
- }
- void SetPred(BasicBlock * block)
- {
- predBlock = block;
- }
- BasicBlock * GetSucc(void) const
- {
- return succBlock;
- }
- void SetSucc(BasicBlock * block)
- {
- succBlock = block;
- }
- PathDependentInfo * GetPathDependentInfo() const
- {
- return pathDependentInfo;
- }
- void SetPathDependentInfo(const PathDependentInfo &info, JitArenaAllocator *const alloc)
- {
- Assert(info.HasInfo());
- if (!pathDependentInfo)
- {
- pathDependentInfo = JitAnew(alloc, PathDependentInfo, info);
- }
- else
- {
- *pathDependentInfo = info;
- }
- }
- void ClearPathDependentInfo(JitArenaAllocator * alloc)
- {
- JitAdelete(alloc, pathDependentInfo);
- pathDependentInfo = nullptr;
- }
- private:
- BasicBlock * predBlock;
- BasicBlock * succBlock;
- // Only valid during globopt
- PathDependentInfo * pathDependentInfo;
- };
- class Loop
- {
- friend FlowGraph;
- private:
- typedef JsUtil::BaseDictionary<SymID, StackSym *, JitArenaAllocator, PowerOf2SizePolicy> FieldHoistSymMap;
- typedef JsUtil::BaseDictionary<PropertySym *, Value *, JitArenaAllocator> InitialValueFieldMap;
- Js::ImplicitCallFlags implicitCallFlags;
- Js::LoopFlags loopFlags;
- BasicBlock * headBlock;
- public:
- Func * topFunc;
- uint32 loopNumber;
- SList<BasicBlock *> blockList;
- Loop * next;
- Loop * parent;
- BasicBlock * landingPad;
- IR::LabelInstr * loopTopLabel;
- BVSparse<JitArenaAllocator> *varSymsOnEntry;
- BVSparse<JitArenaAllocator> *int32SymsOnEntry;
- BVSparse<JitArenaAllocator> *lossyInt32SymsOnEntry; // see GlobOptData::liveLossyInt32Syms
- BVSparse<JitArenaAllocator> *float64SymsOnEntry;
- BVSparse<JitArenaAllocator> *liveFieldsOnEntry;
- // SIMD_JS
- // live syms upon entering loop header (from pred merge + forced syms + used before defs in loop)
- BVSparse<JitArenaAllocator> *simd128F4SymsOnEntry;
- BVSparse<JitArenaAllocator> *simd128I4SymsOnEntry;
- BVSparse<JitArenaAllocator> *symsUsedBeforeDefined; // stack syms that are live in the landing pad, and used before they are defined in the loop
- BVSparse<JitArenaAllocator> *likelyIntSymsUsedBeforeDefined; // stack syms that are live in the landing pad with a likely-int value, and used before they are defined in the loop
- BVSparse<JitArenaAllocator> *likelyNumberSymsUsedBeforeDefined; // stack syms that are live in the landing pad with a likely-number value, and used before they are defined in the loop
- // SIMD_JS
- BVSparse<JitArenaAllocator> *likelySimd128F4SymsUsedBeforeDefined; // stack syms that are live in the landing pad with a likely-Simd128F4 value, and used before they are defined in the loop
- BVSparse<JitArenaAllocator> *likelySimd128I4SymsUsedBeforeDefined; // stack syms that are live in the landing pad with a likely-Simd128I4 value, and used before they are defined in the loop
- BVSparse<JitArenaAllocator> *forceFloat64SymsOnEntry;
- // SIMD_JS
- // syms need to be forced to certain type due to hoisting
- BVSparse<JitArenaAllocator> *forceSimd128F4SymsOnEntry;
- BVSparse<JitArenaAllocator> *forceSimd128I4SymsOnEntry;
- BVSparse<JitArenaAllocator> *symsDefInLoop;
- BailOutInfo * bailOutInfo;
- IR::BailOutInstr * toPrimitiveSideEffectCheck;
- BVSparse<JitArenaAllocator> * fieldHoistCandidates;
- BVSparse<JitArenaAllocator> * liveInFieldHoistCandidates;
- BVSparse<JitArenaAllocator> * fieldHoistCandidateTypes;
- SListBase<IR::Instr *> prepassFieldHoistInstrCandidates;
- FieldHoistSymMap fieldHoistSymMap;
- IR::Instr * endDisableImplicitCall;
- BVSparse<JitArenaAllocator> * hoistedFields;
- BVSparse<JitArenaAllocator> * hoistedFieldCopySyms;
- BVSparse<JitArenaAllocator> * liveOutFields;
- ValueNumber firstValueNumberInLoop;
- JsArrayKills jsArrayKills;
- BVSparse<JitArenaAllocator> *fieldKilled;
- BVSparse<JitArenaAllocator> *fieldPRESymStore;
- InitialValueFieldMap initialValueFieldMap;
- InductionVariableSet *inductionVariables;
- BasicBlock *dominatingLoopCountableBlock;
- LoopCount *loopCount;
- SymIdToStackSymMap *loopCountBasedBoundBaseSyms;
- bool isDead : 1;
- bool hasDeadStoreCollectionPass : 1;
- bool hasDeadStorePrepass : 1;
- bool hasCall : 1;
- bool hasHoistedFields : 1;
- bool needImplicitCallBailoutChecksForJsArrayCheckHoist : 1;
- bool allFieldsKilled : 1;
- bool isLeaf : 1;
- bool isProcessed : 1; // Set and reset at varying places according to the phase we're in.
- // For example, in the lowerer, it'll be set to true when we process the loopTop for a certain loop
- struct MemCopyCandidate;
- struct MemSetCandidate;
- struct MemOpCandidate
- {
- SymID base;
- SymID index;
- byte count;
- bool bIndexAlreadyChanged;
- enum MemOpType
- {
- MEMSET,
- MEMCOPY
- } type;
- bool IsMemSet() const { return type == MEMSET; }
- bool IsMemCopy() const { return type == MEMCOPY; }
- struct Loop::MemCopyCandidate* AsMemCopy();
- struct Loop::MemSetCandidate* AsMemSet();
- MemOpCandidate(MemOpType type) :
- type(type)
- {
- }
- };
- struct MemSetCandidate : public MemOpCandidate
- {
- BailoutConstantValue constant;
- StackSym* varSym;
- MemSetCandidate() : MemOpCandidate(MemOpCandidate::MEMSET), varSym(nullptr) {}
- };
- struct MemCopyCandidate : public MemOpCandidate
- {
- SymID ldBase;
- StackSym* transferSym;
- byte ldCount;
- MemCopyCandidate() : MemOpCandidate(MemOpCandidate::MEMCOPY) {}
- };
- #define FOREACH_MEMOP_CANDIDATES_EDITING(data, loop, iterator) FOREACH_SLISTCOUNTED_ENTRY_EDITING(Loop::MemOpCandidate*, data, loop->memOpInfo->candidates, iterator)
- #define NEXT_MEMOP_CANDIDATE_EDITING NEXT_SLISTCOUNTED_ENTRY_EDITING
- #define FOREACH_MEMOP_CANDIDATES(data, loop) FOREACH_SLISTCOUNTED_ENTRY(Loop::MemOpCandidate*, data, loop->memOpInfo->candidates)
- #define NEXT_MEMOP_CANDIDATE NEXT_SLISTCOUNTED_ENTRY
- #define MEMOP_CANDIDATE_TYPE_CHECK(candidate, data, type) if(candidate->Is ## type()) {Loop:: ## type ## Candidate* data = candidate->As## type();
- #define FOREACH_MEMCOPY_CANDIDATES_EDITING(data, loop, iterator) {FOREACH_MEMOP_CANDIDATES_EDITING(_memopCandidate, loop, iterator) {MEMOP_CANDIDATE_TYPE_CHECK(_memopCandidate, data, MemCopy)
- #define NEXT_MEMCOPY_CANDIDATE_EDITING }}NEXT_MEMOP_CANDIDATE_EDITING}
- #define FOREACH_MEMCOPY_CANDIDATES(data, loop) {FOREACH_MEMOP_CANDIDATES(_memopCandidate, loop) {MEMOP_CANDIDATE_TYPE_CHECK(_memopCandidate, data, MemCopy)
- #define NEXT_MEMCOPY_CANDIDATE }}NEXT_MEMOP_CANDIDATE}
- #define FOREACH_MEMSET_CANDIDATES_EDITING(data, loop, iterator) {FOREACH_MEMOP_CANDIDATES_EDITING(_memopCandidate, loop, iterator) {MEMOP_CANDIDATE_TYPE_CHECK(_memopCandidate, data, MemSet)
- #define NEXT_MEMSET_CANDIDATE_EDITING }}NEXT_MEMOP_CANDIDATE_EDITING}
- #define FOREACH_MEMSET_CANDIDATES(data, loop) {FOREACH_MEMOP_CANDIDATES(_memopCandidate, loop) {MEMOP_CANDIDATE_TYPE_CHECK(_memopCandidate, data, MemSet)
- #define NEXT_MEMSET_CANDIDATE }}NEXT_MEMOP_CANDIDATE}
- typedef struct
- {
- byte unroll : 7;
- byte isIncremental : 1;
- } InductionVariableChangeInfo;
- typedef JsUtil::BaseDictionary<SymID, InductionVariableChangeInfo, JitArenaAllocator> InductionVariableChangeInfoMap;
- typedef JsUtil::BaseDictionary<byte, IR::Opnd*, JitArenaAllocator> InductionVariableOpndPerUnrollMap;
- typedef SListCounted<MemOpCandidate *> MemOpList;
- typedef struct
- {
- MemOpList *candidates;
- bool doMemOp : 1;
- BVSparse<JitArenaAllocator> *inductionVariablesUsedAfterLoop;
- InductionVariableChangeInfoMap *inductionVariableChangeInfoMap;
- InductionVariableOpndPerUnrollMap *inductionVariableOpndPerUnrollMap;
- // This assumes that all memop operation use the same index and has the same length
- // Temporary map to reuse existing startIndexOpnd while emiting
- // 0 = !increment & !alreadyChanged, 1 = !increment & alreadyChanged, 2 = increment & !alreadyChanged, 3 = increment & alreadyChanged
- IR::RegOpnd* startIndexOpndCache[4];
- } MemOpInfo;
- MemOpInfo *memOpInfo;
- struct RegAlloc
- {
- Lifetime ** loopTopRegContent; // Save off the state of the registers at the loop top
- BVSparse<JitArenaAllocator> * symRegUseBv; // If a lifetime was live in a reg into the loop, did the reg get used before being spilled?
- BVSparse<JitArenaAllocator> * defdInLoopBv; // Was a lifetime defined in the loop?
- BVSparse<JitArenaAllocator> * liveOnBackEdgeSyms; // Is a lifetime live on the back-edge of the loop?
- BitVector regUseBv; // Registers used in this loop so far
- uint32 loopStart; // loopTopLabel->GetNumber()
- uint32 loopEnd; // loopTailBranch->GetNumber()
- uint32 helperLength; // Number of instrs in helper code in loop
- SList<Lifetime *> * extendedLifetime; // Lifetimes to extend for this loop
- SList<Lifetime **> * exitRegContentList; // Linked list of regContents for the exit edges
- bool hasNonOpHelperCall;
- bool hasCall;
- bool hasAirLock; // Do back-edges have airlock blocks?
- } regAlloc;
- public:
- Loop(JitArenaAllocator * alloc, Func *func)
- : topFunc(func),
- blockList(alloc),
- parent(nullptr),
- landingPad(nullptr),
- loopTopLabel(nullptr),
- symsUsedBeforeDefined(nullptr),
- likelyIntSymsUsedBeforeDefined(nullptr),
- likelyNumberSymsUsedBeforeDefined(nullptr),
- likelySimd128F4SymsUsedBeforeDefined(nullptr),
- likelySimd128I4SymsUsedBeforeDefined(nullptr),
- forceFloat64SymsOnEntry(nullptr),
- forceSimd128F4SymsOnEntry(nullptr),
- forceSimd128I4SymsOnEntry(nullptr),
- symsDefInLoop(nullptr),
- fieldHoistCandidateTypes(nullptr),
- fieldHoistSymMap(alloc),
- needImplicitCallBailoutChecksForJsArrayCheckHoist(false),
- inductionVariables(nullptr),
- dominatingLoopCountableBlock(nullptr),
- loopCount(nullptr),
- loopCountBasedBoundBaseSyms(nullptr),
- isDead(false),
- allFieldsKilled(false),
- isLeaf(true),
- isProcessed(false),
- initialValueFieldMap(alloc)
- {
- this->loopNumber = ++func->loopCount;
- }
- void SetHeadBlock(BasicBlock *block) { headBlock = block; }
- BasicBlock * GetHeadBlock() const { Assert(headBlock == blockList.Head()); return headBlock; }
- bool IsDescendentOrSelf(Loop const * loop) const;
- bool EnsureMemOpVariablesInitialized();
- Js::ImplicitCallFlags GetImplicitCallFlags();
- void SetImplicitCallFlags(Js::ImplicitCallFlags flags);
- Js::LoopFlags GetLoopFlags() const { return loopFlags; }
- void SetLoopFlags(Js::LoopFlags val) { loopFlags = val; }
- bool CanHoistInvariants();
- bool CanDoFieldCopyProp();
- bool CanDoFieldHoist();
- void SetHasCall();
- IR::LabelInstr * GetLoopTopInstr() const;
- void SetLoopTopInstr(IR::LabelInstr * loopTop);
- Func * GetFunc() const { return GetLoopTopInstr()->m_func; }
- #if DBG_DUMP
- bool GetHasCall() const { return hasCall; }
- uint GetLoopNumber() const;
- #endif
- private:
- void InsertLandingPad(FlowGraph *fg);
- bool RemoveBreakBlocks(FlowGraph *fg);
- };
- // Structure definition cannot be inside Loop in order to use it as a parameter in GlobOpt
- struct MemOpEmitData
- {
- Loop::MemOpCandidate* candidate;
- IR::Instr* stElemInstr;
- BasicBlock* block;
- Loop::InductionVariableChangeInfo inductionVar;
- IR::BailOutKind bailOutKind;
- };
- struct MemSetEmitData : public MemOpEmitData
- {
- };
- struct MemCopyEmitData : public MemOpEmitData
- {
- IR::Instr* ldElemInstr;
- };
- #define FOREACH_BLOCK_IN_FUNC(block, func)\
- FOREACH_BLOCK(block, func->m_fg)
- #define NEXT_BLOCK_IN_FUNC\
- NEXT_BLOCK;
- #define FOREACH_BLOCK_IN_FUNC_DEAD_OR_ALIVE(block, func)\
- FOREACH_BLOCK_DEAD_OR_ALIVE(block, func->m_fg)
- #define NEXT_BLOCK_IN_FUNC_DEAD_OR_ALIVE\
- NEXT_BLOCK_DEAD_OR_ALIVE;
- #define FOREACH_BLOCK_BACKWARD_IN_FUNC(block, func) \
- FOREACH_BLOCK_BACKWARD(block, func->m_fg)
- #define NEXT_BLOCK_BACKWARD_IN_FUNC \
- NEXT_BLOCK_BACKWARD;
- #define FOREACH_BLOCK_BACKWARD_IN_FUNC_DEAD_OR_ALIVE(block, func) \
- FOREACH_BLOCK_BACKWARD_DEAD_OR_ALIVE(block, func->m_fg)
- #define NEXT_BLOCK_BACKWARD_IN_FUNC_DEAD_OR_ALIVE \
- NEXT_BLOCK_BACKWARD_DEAD_OR_ALIVE;
- #define FOREACH_BLOCK_IN_FUNC_EDITING(block, func)\
- FOREACH_BLOCK_EDITING(block, func->m_fg)
- #define NEXT_BLOCK_IN_FUNC_EDITING\
- NEXT_BLOCK_EDITING;
- #define FOREACH_BLOCK_BACKWARD_IN_FUNC_EDITING(block, func)\
- FOREACH_BLOCK_BACKWARD_EDITING(block, func->m_fg)
- #define NEXT_BLOCK_BACKWARD_IN_FUNC_EDITING\
- NEXT_BLOCK_BACKWARD_EDITING;
- #define FOREACH_BLOCK_ALL(block, graph) \
- for (BasicBlock *block = graph->blockList;\
- block != nullptr;\
- block = block->next)\
- {
- #define NEXT_BLOCK_ALL \
- }
- #define FOREACH_BLOCK(block, graph)\
- FOREACH_BLOCK_ALL(block, graph) \
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK \
- NEXT_BLOCK_ALL
- #define FOREACH_BLOCK_DEAD_OR_ALIVE(block, graph)\
- FOREACH_BLOCK_ALL(block, graph) \
- if (block->isDeleted && !block->isDead) { continue; }
- #define NEXT_BLOCK_DEAD_OR_ALIVE \
- NEXT_BLOCK_ALL
- #define FOREACH_BLOCK_BACKWARD(block, graph)\
- FOREACH_BLOCK_BACKWARD_IN_RANGE(block, graph->tailBlock, nullptr)
- #define NEXT_BLOCK_BACKWARD \
- NEXT_BLOCK_BACKWARD_IN_RANGE
- #define FOREACH_BLOCK_BACKWARD_DEAD_OR_ALIVE(block, graph)\
- FOREACH_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE(block, graph->tailBlock, nullptr)
- #define NEXT_BLOCK_BACKWARD_DEAD_OR_ALIVE \
- NEXT_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE
- #define FOREACH_BLOCK_BACKWARD_IN_RANGE_ALL(block, blockList, blockLast)\
- {\
- BasicBlock * blockStop = blockLast? ((BasicBlock *)blockLast)->prev : nullptr; \
- for (BasicBlock *block = blockList;\
- block != blockStop;\
- block = block->prev)\
- {
- #define NEXT_BLOCK_BACKWARD_IN_RANGE_ALL \
- }}
- #define FOREACH_BLOCK_BACKWARD_IN_RANGE(block, blockList, blockLast) \
- FOREACH_BLOCK_BACKWARD_IN_RANGE_ALL(block, blockList, blockLast) \
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_BACKWARD_IN_RANGE \
- NEXT_BLOCK_BACKWARD_IN_RANGE_ALL
- #define FOREACH_BLOCK_BACKWARD_IN_RANGE_ALL_EDITING(block, blockList, blockLast, blockPrev)\
- {\
- BasicBlock *blockPrev;\
- BasicBlock * blockStop = blockLast? ((BasicBlock *)blockLast)->prev : nullptr; \
- for (BasicBlock *block = blockList;\
- block != blockStop;\
- block = blockPrev)\
- {\
- blockPrev = block->prev;
- #define NEXT_BLOCK_BACKWARD_IN_RANGE_ALL_EDITING \
- }}
- #define FOREACH_BLOCK_BACKWARD_IN_RANGE_EDITING(block, blockList, blockLast, blockPrev) \
- FOREACH_BLOCK_BACKWARD_IN_RANGE_ALL_EDITING(block, blockList, blockLast, blockPrev) \
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_BACKWARD_IN_RANGE_EDITING \
- NEXT_BLOCK_BACKWARD_IN_RANGE_ALL_EDITING
- #define FOREACH_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE(block, blockList, blockLast) \
- FOREACH_BLOCK_BACKWARD_IN_RANGE_ALL(block, blockList, blockLast) \
- if (block->isDeleted && !block->isDead) { continue; }
- #define NEXT_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE \
- NEXT_BLOCK_BACKWARD_IN_RANGE_ALL
- #define FOREACH_BLOCK_EDITING(block, graph)\
- {\
- BasicBlock *blockNext;\
- for (BasicBlock *block = graph->blockList;\
- block != nullptr;\
- block = blockNext)\
- {\
- blockNext = block->next; \
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_EDITING \
- }}
- #define FOREACH_BLOCK_BACKWARD_EDITING(block, graph)\
- {\
- BasicBlock *blockPrev;\
- for (BasicBlock *block = graph->tailBlock;\
- block != nullptr;\
- block = blockPrev)\
- {\
- blockPrev = block->prev; \
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_BACKWARD_EDITING \
- }}
- #define FOREACH_BLOCK_IN_LIST(block, list)\
- FOREACH_SLIST_ENTRY(BasicBlock*, block, list)\
- {\
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_IN_LIST \
- NEXT_SLIST_ENTRY \
- }
- #define FOREACH_BLOCK_IN_LIST_EDITING(block, list, iter)\
- FOREACH_SLIST_ENTRY_EDITING(BasicBlock*, block, list, iter)\
- {\
- if (block->isDeleted) { continue; }
- #define NEXT_BLOCK_IN_LIST_EDITING \
- NEXT_SLIST_ENTRY_EDITING \
- }
- #define FOREACH_SUCCESSOR_EDGE(edge, block)\
- FOREACH_EDGE_IN_LIST(edge, block->GetSuccList())
- #define NEXT_SUCCESSOR_EDGE\
- NEXT_EDGE_IN_LIST
- #define FOREACH_SUCCESSOR_EDGE_EDITING(edge, bloc, iter)\
- FOREACH_EDGE_IN_LIST_EDITING(edge, block->GetSuccList(), iter)
- #define NEXT_SUCCESSOR_EDGE_EDITING\
- NEXT_EDGE_IN_LIST_EDITING
- #define FOREACH_PREDECESSOR_EDGE(edge, block)\
- FOREACH_EDGE_IN_LIST(edge, block->GetPredList())
- #define NEXT_PREDECESSOR_EDGE\
- NEXT_EDGE_IN_LIST
- #define FOREACH_PREDECESSOR_EDGE_EDITING(edge, block, iter)\
- FOREACH_EDGE_IN_LIST_EDITING(edge, block->GetPredList(), iter)
- #define NEXT_PREDECESSOR_EDGE_EDITING\
- NEXT_EDGE_IN_LIST_EDITING
- #define FOREACH_EDGE_IN_LIST(edge, list)\
- FOREACH_SLISTBASECOUNTED_ENTRY(FlowEdge*, edge, list)\
- {
- #define NEXT_EDGE_IN_LIST\
- NEXT_SLISTBASECOUNTED_ENTRY }
- #define FOREACH_EDGE_IN_LIST_EDITING(edge, list, iter)\
- FOREACH_SLISTBASECOUNTED_ENTRY_EDITING(FlowEdge*, edge, list, iter)\
- {\
- #define NEXT_EDGE_IN_LIST_EDITING\
- NEXT_SLISTBASECOUNTED_ENTRY_EDITING }
- #define FOREACH_SUCCESSOR_BLOCK(blockSucc, block)\
- FOREACH_EDGE_IN_LIST(__edge, block->GetSuccList())\
- {\
- BasicBlock * blockSucc = __edge->GetSucc(); \
- AnalysisAssert(blockSucc);
- #define NEXT_SUCCESSOR_BLOCK\
- }\
- NEXT_EDGE_IN_LIST
- #define FOREACH_SUCCESSOR_BLOCK_EDITING(blockSucc, block, iter)\
- FOREACH_EDGE_IN_LIST_EDITING(__edge, block->GetSuccList(), iter)\
- {\
- BasicBlock * blockSucc = __edge->GetSucc(); \
- AnalysisAssert(blockSucc);
- #define NEXT_SUCCESSOR_BLOCK_EDITING\
- }\
- NEXT_EDGE_IN_LIST_EDITING
- #define FOREACH_DEAD_SUCCESSOR_BLOCK(blockSucc, block)\
- FOREACH_EDGE_IN_LIST(__edge, block->GetDeadSuccList())\
- {\
- BasicBlock * blockSucc = __edge->GetSucc(); \
- AnalysisAssert(blockSucc);
- #define NEXT_DEAD_SUCCESSOR_BLOCK\
- }\
- NEXT_EDGE_IN_LIST
- #define FOREACH_PREDECESSOR_BLOCK(blockPred, block)\
- FOREACH_EDGE_IN_LIST(__edge, block->GetPredList())\
- {\
- BasicBlock * blockPred = __edge->GetPred(); \
- AnalysisAssert(blockPred);
- #define NEXT_PREDECESSOR_BLOCK\
- }\
- NEXT_EDGE_IN_LIST
- #define FOREACH_DEAD_PREDECESSOR_BLOCK(blockPred, block)\
- FOREACH_EDGE_IN_LIST(__edge, block->GetDeadPredList())\
- {\
- BasicBlock * blockPred = __edge->GetPred(); \
- AnalysisAssert(blockPred);
- #define NEXT_DEAD_PREDECESSOR_BLOCK\
- }\
- NEXT_EDGE_IN_LIST
- #define FOREACH_BLOCK_IN_LOOP(block, loop)\
- FOREACH_BLOCK_IN_LIST(block, &loop->blockList)
- #define NEXT_BLOCK_IN_LOOP \
- NEXT_BLOCK_IN_LIST
- #define FOREACH_BLOCK_IN_LOOP_EDITING(block, loop, iter)\
- FOREACH_BLOCK_IN_LIST_EDITING(block, &loop->blockList, iter)
- #define NEXT_BLOCK_IN_LOOP_EDITING \
- NEXT_BLOCK_IN_LIST_EDITING
- #define FOREACH_LOOP_IN_FUNC_EDITING(loop, func)\
- FOREACH_LOOP_EDITING(loop, func->m_fg)
- #define NEXT_LOOP_IN_FUNC_EDITING\
- NEXT_LOOP_EDITING;
- #define FOREACH_LOOP_EDITING(loop, graph)\
- {\
- Loop* loopNext;\
- for (Loop* loop = graph->loopList;\
- loop != nullptr;\
- loop = loopNext)\
- {\
- loopNext = loop->next;
- #define NEXT_LOOP_EDITING \
- }}
|