LinearScan.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #include "LinearScanMDShared.h"
  7. #include "LinearScanMD.h"
  8. #if DBG_DUMP || ENABLE_DEBUG_CONFIG_OPTIONS
  9. extern char const * const RegNames[];
  10. extern wchar_t const * const RegNamesW[];
  11. #endif
  12. class OpHelperBlock;
  13. struct FillBailOutState;
  14. struct GlobalBailOutRecordDataTable;
  15. struct GlobalBailOutRecordDataRow;
  16. #define INT_REG_COUNT (FIRST_FLOAT_REG - 1)
  17. #define FLOAT_REG_COUNT (RegNumCount - FIRST_FLOAT_REG)
  18. struct StackSlot
  19. {
  20. int32 offset;
  21. uint32 size;
  22. uint32 lastUse;
  23. };
  24. class LoweredBasicBlock
  25. {
  26. public:
  27. JsUtil::List<Lifetime*, JitArenaAllocator> inlineeFrameLifetimes;
  28. typedef JsUtil::BaseDictionary<SymID, uint, JitArenaAllocator> InlineeFrameSymsDictionary;
  29. InlineeFrameSymsDictionary inlineeFrameSyms;
  30. JsUtil::List<Func*, JitArenaAllocator> inlineeStack;
  31. LoweredBasicBlock(JitArenaAllocator* allocator) : inlineeFrameLifetimes(allocator), inlineeStack(allocator), inlineeFrameSyms(allocator)
  32. {
  33. }
  34. static LoweredBasicBlock* New(JitArenaAllocator * allocator);
  35. void Copy(LoweredBasicBlock* block);
  36. LoweredBasicBlock* Clone(JitArenaAllocator * allocator);
  37. bool HasData();
  38. bool Equals(LoweredBasicBlock* block);
  39. };
  40. class LinearScan
  41. {
  42. friend class LinearScanMDShared;
  43. friend class LinearScanMD;
  44. private:
  45. Func * func;
  46. JitArenaAllocator * tempAlloc;
  47. IR::Instr * currentInstr;
  48. uint32 currentBlockNumber;
  49. BitVector activeRegs;
  50. BitVector int32Regs;
  51. uint32 numInt32Regs;
  52. BitVector floatRegs;
  53. uint32 numFloatRegs;
  54. BitVector callerSavedRegs;
  55. BitVector calleeSavedRegs;
  56. BitVector tempRegs;
  57. BitVector instrUseRegs;
  58. BitVector secondChanceRegs;
  59. BitVector callSetupRegs;
  60. SList<Lifetime *> * activeLiveranges;
  61. SList<Lifetime *> * lifetimeList;
  62. uint intRegUsedCount;
  63. uint floatRegUsedCount;
  64. int loopNest;
  65. uint32 m_bailOutRecordCount;
  66. Loop * curLoop;
  67. Region * currentRegion;
  68. BVSparse<JitArenaAllocator> *liveOnBackEdgeSyms;
  69. GlobalBailOutRecordDataTable **globalBailOutRecordTables;
  70. uint ** lastUpdatedRowIndices; // A temporary array of indices keeping track of which entry on the global table was updated for a regSlot by the last bailout point
  71. LinearScanMD linearScanMD;
  72. SList<OpHelperBlock> * opHelperBlockList;
  73. SList<OpHelperBlock>::Iterator opHelperBlockIter;
  74. OpHelperBlock * currentOpHelperBlock;
  75. uint totalOpHelperFullVisitedLength;
  76. BitVector opHelperSpilledRegs;
  77. SList<Lifetime *> * opHelperSpilledLiveranges;
  78. Lifetime * tempRegLifetimes[RegNumCount];
  79. Lifetime * regContent[RegNumCount];
  80. IR::LabelInstr * lastLabel;
  81. SList<Lifetime *> * stackPackInUseLiveRanges;
  82. SList<StackSlot *> *stackSlotsFreeList;
  83. LoweredBasicBlock *currentBlock;
  84. #if DBG
  85. BitVector nonAllocatableRegs;
  86. #endif
  87. public:
  88. LinearScan(Func *func) : func(func), currentBlockNumber(0), loopNest(0), intRegUsedCount(0), floatRegUsedCount(0), activeLiveranges(NULL),
  89. linearScanMD(func), opHelperSpilledLiveranges(NULL), currentOpHelperBlock(NULL),
  90. lastLabel(NULL), numInt32Regs(0), numFloatRegs(0), stackPackInUseLiveRanges(NULL), stackSlotsFreeList(NULL),
  91. totalOpHelperFullVisitedLength(0), curLoop(NULL), currentBlock(nullptr), currentRegion(nullptr), m_bailOutRecordCount(0),
  92. globalBailOutRecordTables(nullptr), lastUpdatedRowIndices(nullptr)
  93. {
  94. linearScanMD.Init(this);
  95. }
  96. void RegAlloc();
  97. JitArenaAllocator * GetTempAlloc();
  98. static uint8 GetRegAttribs(RegNum reg);
  99. static IRType GetRegType(RegNum reg);
  100. static bool IsCalleeSaved(RegNum reg);
  101. static uint GetUseSpillCost(uint loopNest, BOOL isInHelperBlock);
  102. bool IsCallerSaved(RegNum reg) const;
  103. bool IsAllocatable(RegNum reg) const;
  104. private:
  105. void Init();
  106. bool SkipNumberedInstr(IR::Instr *instr);
  107. void EndDeadLifetimes(IR::Instr *instr);
  108. void EndDeadOpHelperLifetimes(IR::Instr *instr);
  109. void AllocateNewLifetimes(IR::Instr *instr);
  110. RegNum Spill(Lifetime *newLifetime, IR::RegOpnd *regOpnd, bool dontSpillCurrent, bool force);
  111. void SpillReg(RegNum reg, bool forceSpill = false);
  112. RegNum SpillLiveRange(Lifetime * spilledRange, IR::Instr *insertionInstr = NULL);
  113. void ProcessEHRegionBoundary(IR::Instr * instr);
  114. void AllocateStackSpace(Lifetime *spilledRange);
  115. RegNum FindReg(Lifetime *newLifetime, IR::RegOpnd *regOpnd, bool force = false);
  116. BVIndex GetPreferencedRegIndex(Lifetime *lifetime, BitVector freeRegs);
  117. void AddToActive(Lifetime *liveRange);
  118. void InsertStores(Lifetime *lifetime, RegNum reg, IR::Instr *insertionInstr);
  119. void InsertStore(IR::Instr *instr, StackSym *sym, RegNum reg);
  120. void InsertLoads(StackSym *sym, RegNum reg);
  121. void InsertLoad(IR::Instr *instr, StackSym *sym, RegNum reg);
  122. void SetDstReg(IR::Instr *instr);
  123. void SetSrcRegs(IR::Instr *instr);
  124. void SetUses(IR::Instr *instr, IR::Opnd *opnd);
  125. void SetUse(IR::Instr *instr, IR::RegOpnd *opnd);
  126. void PrepareForUse(Lifetime * lifetime);
  127. void RecordUse(Lifetime * lifetime, IR::Instr * instr, IR::RegOpnd * regOpnd, bool isFromBailout = false);
  128. void RecordLoopUse(Lifetime *lifetime, RegNum reg);
  129. void RecordDef(Lifetime *const lifetime, IR::Instr *const instr, const uint32 useCountCost);
  130. void SetReg(IR::RegOpnd *regOpnd);
  131. void KillImplicitRegs(IR::Instr *instr);
  132. bool CheckIfInLoop(IR::Instr *instr);
  133. uint GetSpillCost(Lifetime * lifetime);
  134. bool RemoveDeadStores(IR::Instr *instr);
  135. // This helper function is used to save bytecode stack sym value to memory / local slots on stack so that we can read it for the locals inspection.
  136. void WriteThroughForLocal(IR::RegOpnd* regOpnd, Lifetime* lifetime, IR::Instr* instrInsertAfter);
  137. int32 GetStackOffset(Js::RegSlot regSlotId);
  138. bool IsSymNonTempLocalVar(StackSym *sym);
  139. bool NeedsWriteThrough(StackSym * sym);
  140. bool NeedsWriteThroughForEH(StackSym * sym);
  141. bool IsInLoop() { return this->loopNest != 0; }
  142. bool IsInHelperBlock() const { return this->currentOpHelperBlock != NULL; }
  143. uint HelperBlockStartInstrNumber() const;
  144. uint HelperBlockEndInstrNumber() const;
  145. void CheckOpHelper(IR::Instr * instr);
  146. void InsertOpHelperSpillAndRestores();
  147. void InsertOpHelperSpillAndRestores(OpHelperBlock const& opHelperBlock);
  148. void AssignActiveReg(Lifetime * lifetime, RegNum reg);
  149. void AssignTempReg(Lifetime * lifetime, RegNum reg);
  150. RegNum GetAssignedTempReg(Lifetime * lifetime, IRType type);
  151. void AddOpHelperSpilled(Lifetime * liveRange);
  152. void RemoveOpHelperSpilled(Lifetime * lifetime);
  153. void SetCantOpHelperSpill(Lifetime * lifetime);
  154. static void AddLiveRange(SList<Lifetime *> * list, Lifetime * liverange);
  155. static Lifetime * RemoveRegLiveRange(SList<Lifetime *> * list, RegNum reg);
  156. GlobalBailOutRecordDataTable * EnsureGlobalBailOutRecordTable(Func *func);
  157. void FillBailOutRecord(IR::Instr * instr);
  158. void FillBailOutOffset(int * offset, StackSym * stackSym, FillBailOutState * state, IR::Instr * instr);
  159. void FillStackLiteralBailOutRecord(IR::Instr * instr, BailOutInfo * bailOutInfo, struct FuncBailOutData * funcBailOutData, uint funcCount);
  160. template <typename Fn>
  161. void ForEachStackLiteralBailOutInfo(IR::Instr * instr, BailOutInfo * bailOutInfo, FuncBailOutData * funcBailOutData, uint funcCount, Fn fn);
  162. void ProcessSecondChanceBoundary(IR::BranchInstr *branchInstr);
  163. void ProcessSecondChanceBoundaryHelper(IR::BranchInstr *branchInstr, IR::LabelInstr *branchLabel);
  164. void ProcessSecondChanceBoundary(IR::LabelInstr *labelInstr);
  165. void InsertSecondChanceCompensation(Lifetime ** branchRegContent, Lifetime **labelRegContent,
  166. IR::BranchInstr *branchInstr, IR::LabelInstr *labelInstr);
  167. IR::Instr * EnsureAirlock(bool needsAirlock, bool *pHasAirlock, IR::Instr *insertionInstr, IR::Instr **pInsertionStartInstr, IR::BranchInstr *branchInstr, IR::LabelInstr *labelInstr);
  168. bool NeedsLoopBackEdgeCompensation(Lifetime *lifetime, IR::LabelInstr *loopTopLabel);
  169. void ReconcileRegContent(Lifetime ** branchRegContent, Lifetime **labelRegContent,
  170. IR::BranchInstr *branchInstr, IR::LabelInstr *labelInstr,
  171. Lifetime *lifetime, RegNum reg, BitVector *thrashedRegs, IR::Instr *insertionInstr, IR::Instr* insertionStartInstr);
  172. void AvoidCompensationConflicts(IR::LabelInstr *labelInstr, IR::BranchInstr *branchInstr,
  173. Lifetime *labelRegContent[], Lifetime *branchRegContent[],
  174. IR::Instr **pInsertionInstr, IR::Instr **pInsertionStartInstr, bool needsAirlock, bool *pHasAirlock);
  175. RegNum SecondChanceAllocation(Lifetime *lifetime, bool force);
  176. void SecondChanceAllocateToReg(Lifetime *lifetime, RegNum reg);
  177. IR::Instr * InsertAirlock(IR::BranchInstr *branchInstr, IR::LabelInstr *labelInstr);
  178. void SaveRegContent(IR::Instr *instr);
  179. bool RegsAvailable(IRType type);
  180. void SpillInlineeArgs(IR::Instr* instr);
  181. void TrackInlineeArgLifetimes(IR::Instr* instr);
  182. uint GetRemainingHelperLength(Lifetime *const lifetime);
  183. uint CurrentOpHelperVisitedLength(IR::Instr *const currentInstr) const;
  184. IR::Instr * TryHoistLoad(IR::Instr *instr, Lifetime *lifetime);
  185. bool ClearLoopExitIfRegUnused(Lifetime *lifetime, RegNum reg, IR::BranchInstr *branchInstr, Loop *loop);
  186. #if DBG
  187. void CheckInvariants() const;
  188. #endif
  189. #if DBG_DUMP
  190. void PrintStats() const;
  191. #endif
  192. #if ENABLE_DEBUG_CONFIG_OPTIONS
  193. IR::Instr * GetIncInsertionPoint(IR::Instr *instr);
  194. void DynamicStatsInstrument();
  195. #endif
  196. static IR::Instr * InsertMove(IR::Opnd *dst, IR::Opnd *src, IR::Instr *const insertBeforeInstr);
  197. };