GlobOpt.h 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. class BackwardPass;
  6. class LoopCount;
  7. class GlobOpt;
  8. #if ENABLE_DEBUG_CONFIG_OPTIONS && DBG_DUMP
  9. #define GOPT_TRACE_OPND(opnd, ...) \
  10. if (PHASE_TRACE(Js::GlobOptPhase, this->func) && !this->IsLoopPrePass()) \
  11. { \
  12. Output::Print(_u("TRACE: ")); \
  13. opnd->Dump(); \
  14. Output::Print(_u(" : ")); \
  15. Output::Print(__VA_ARGS__); \
  16. Output::Flush(); \
  17. }
  18. #define GOPT_TRACE(...) \
  19. if (PHASE_TRACE(Js::GlobOptPhase, this->func) && !this->IsLoopPrePass()) \
  20. { \
  21. Output::Print(_u("TRACE: ")); \
  22. Output::Print(__VA_ARGS__); \
  23. Output::Flush(); \
  24. }
  25. #define GOPT_TRACE_INSTRTRACE(instr) \
  26. if (PHASE_TRACE(Js::GlobOptPhase, this->func) && !this->IsLoopPrePass()) \
  27. { \
  28. instr->Dump(); \
  29. Output::Flush(); \
  30. }
  31. #define GOPT_TRACE_INSTR(instr, ...) \
  32. if (PHASE_TRACE(Js::GlobOptPhase, this->func) && !this->IsLoopPrePass()) \
  33. { \
  34. Output::Print(_u("TRACE: ")); \
  35. Output::Print(__VA_ARGS__); \
  36. instr->Dump(); \
  37. Output::Flush(); \
  38. }
  39. #define GOPT_TRACE_BLOCK(block, before) \
  40. this->Trace(block, before); \
  41. Output::Flush();
  42. // TODO: OOP JIT, add back line number
  43. #define TRACE_PHASE_INSTR(phase, instr, ...) \
  44. if(PHASE_TRACE(phase, this->func)) \
  45. { \
  46. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; \
  47. Output::Print( \
  48. _u("Function %s (%s)"), \
  49. this->func->GetJITFunctionBody()->GetDisplayName(), \
  50. this->func->GetDebugNumberSet(debugStringBuffer)); \
  51. if(this->func->IsLoopBody()) \
  52. { \
  53. Output::Print(_u(", loop %u"), this->func->GetWorkItem()->GetLoopNumber()); \
  54. } \
  55. if(instr->m_func != this->func) \
  56. { \
  57. Output::Print( \
  58. _u(", Inlinee %s (%s)"), \
  59. instr->m_func->GetJITFunctionBody()->GetDisplayName(), \
  60. instr->m_func->GetDebugNumberSet(debugStringBuffer)); \
  61. } \
  62. Output::Print(_u(" - %s\n "), Js::PhaseNames[phase]); \
  63. instr->Dump(); \
  64. Output::Print(_u(" ")); \
  65. Output::Print(__VA_ARGS__); \
  66. Output::Flush(); \
  67. }
  68. #define TRACE_PHASE_INSTR_VERBOSE(phase, instr, ...) \
  69. if(CONFIG_FLAG(Verbose)) \
  70. { \
  71. TRACE_PHASE_INSTR(phase, instr, __VA_ARGS__); \
  72. }
  73. #define TRACE_TESTTRACE_PHASE_INSTR(phase, instr, ...) \
  74. TRACE_PHASE_INSTR(phase, instr, __VA_ARGS__); \
  75. TESTTRACE_PHASE_INSTR(phase, instr, __VA_ARGS__);
  76. #else // ENABLE_DEBUG_CONFIG_OPTIONS && DBG_DUMP
  77. #define GOPT_TRACE(...)
  78. #define GOPT_TRACE_OPND(opnd, ...)
  79. #define GOPT_TRACE_INSTRTRACE(instr)
  80. #define GOPT_TRACE_INSTR(instr, ...)
  81. #define GOPT_TRACE_BLOCK(block, before)
  82. #define TRACE_PHASE_INSTR(phase, instr, ...)
  83. #define TRACE_PHASE_INSTR_VERBOSE(phase, instr, ...)
  84. #define TRACE_TESTTRACE_PHASE_INSTR(phase, instr, ...) TESTTRACE_PHASE_INSTR(phase, instr, __VA_ARGS__);
  85. #endif // ENABLE_DEBUG_CONFIG_OPTIONS && DBG_DUMP
  86. class IntMathExprAttributes : public ExprAttributes
  87. {
  88. private:
  89. static const uint IgnoredIntOverflowIndex = 0;
  90. static const uint IgnoredNegativeZeroIndex = 1;
  91. public:
  92. IntMathExprAttributes(const ExprAttributes &exprAttributes) : ExprAttributes(exprAttributes)
  93. {
  94. }
  95. IntMathExprAttributes(const bool ignoredIntOverflow, const bool ignoredNegativeZero)
  96. {
  97. SetBitAttribute(IgnoredIntOverflowIndex, ignoredIntOverflow);
  98. SetBitAttribute(IgnoredNegativeZeroIndex, ignoredNegativeZero);
  99. }
  100. };
  101. class ConvAttributes : public ExprAttributes
  102. {
  103. private:
  104. static const uint DstUnsignedIndex = 0;
  105. static const uint SrcUnsignedIndex = 1;
  106. public:
  107. ConvAttributes(const ExprAttributes &exprAttributes) : ExprAttributes(exprAttributes)
  108. {
  109. }
  110. ConvAttributes(const bool isDstUnsigned, const bool isSrcUnsigned)
  111. {
  112. SetBitAttribute(DstUnsignedIndex, isDstUnsigned);
  113. SetBitAttribute(SrcUnsignedIndex, isSrcUnsigned);
  114. }
  115. };
  116. class DstIsIntOrNumberAttributes : public ExprAttributes
  117. {
  118. private:
  119. static const uint DstIsIntOnlyIndex = 0;
  120. static const uint DstIsNumberOnlyIndex = 1;
  121. public:
  122. DstIsIntOrNumberAttributes(const ExprAttributes &exprAttributes) : ExprAttributes(exprAttributes)
  123. {
  124. }
  125. DstIsIntOrNumberAttributes(const bool dstIsIntOnly, const bool dstIsNumberOnly)
  126. {
  127. SetBitAttribute(DstIsIntOnlyIndex, dstIsIntOnly);
  128. SetBitAttribute(DstIsNumberOnlyIndex, dstIsNumberOnly);
  129. }
  130. };
  131. enum class PathDependentRelationship : uint8
  132. {
  133. Equal,
  134. NotEqual,
  135. GreaterThanOrEqual,
  136. GreaterThan,
  137. LessThanOrEqual,
  138. LessThan
  139. };
  140. class PathDependentInfo
  141. {
  142. private:
  143. Value *leftValue, *rightValue;
  144. int32 rightConstantValue;
  145. PathDependentRelationship relationship;
  146. public:
  147. PathDependentInfo(const PathDependentRelationship relationship, Value *const leftValue, Value *const rightValue)
  148. : relationship(relationship), leftValue(leftValue), rightValue(rightValue)
  149. {
  150. Assert(leftValue);
  151. Assert(rightValue);
  152. }
  153. PathDependentInfo(
  154. const PathDependentRelationship relationship,
  155. Value *const leftValue,
  156. Value *const rightValue,
  157. const int32 rightConstantValue)
  158. : relationship(relationship), leftValue(leftValue), rightValue(rightValue), rightConstantValue(rightConstantValue)
  159. {
  160. Assert(leftValue);
  161. }
  162. public:
  163. bool HasInfo() const
  164. {
  165. return !!leftValue;
  166. }
  167. PathDependentRelationship Relationship() const
  168. {
  169. Assert(HasInfo());
  170. return relationship;
  171. }
  172. Value *LeftValue() const
  173. {
  174. Assert(HasInfo());
  175. return leftValue;
  176. }
  177. Value *RightValue() const
  178. {
  179. Assert(HasInfo());
  180. return rightValue;
  181. }
  182. int32 RightConstantValue() const
  183. {
  184. Assert(!RightValue());
  185. return rightConstantValue;
  186. }
  187. };
  188. class PathDependentInfoToRestore
  189. {
  190. private:
  191. ValueInfo *leftValueInfo, *rightValueInfo;
  192. public:
  193. PathDependentInfoToRestore() : leftValueInfo(nullptr), rightValueInfo(nullptr)
  194. {
  195. }
  196. PathDependentInfoToRestore(ValueInfo *const leftValueInfo, ValueInfo *const rightValueInfo)
  197. : leftValueInfo(leftValueInfo), rightValueInfo(rightValueInfo)
  198. {
  199. }
  200. public:
  201. ValueInfo *LeftValueInfo() const
  202. {
  203. return leftValueInfo;
  204. }
  205. ValueInfo *RightValueInfo() const
  206. {
  207. return rightValueInfo;
  208. }
  209. public:
  210. void Clear()
  211. {
  212. leftValueInfo = nullptr;
  213. rightValueInfo = nullptr;
  214. }
  215. };
  216. typedef JsUtil::List<IR::Opnd *, JitArenaAllocator> OpndList;
  217. typedef JsUtil::BaseDictionary<Sym *, ValueInfo *, JitArenaAllocator> SymToValueInfoMap;
  218. typedef JsUtil::BaseDictionary<SymID, IR::Instr *, JitArenaAllocator> SymIdToInstrMap;
  219. typedef JsUtil::BaseHashSet<Value *, JitArenaAllocator, PowerOf2SizePolicy, ValueNumber> ValueSetByValueNumber;
  220. typedef JsUtil::BaseDictionary<SymID, StackSym *, JitArenaAllocator> SymIdToStackSymMap;
  221. typedef JsUtil::Pair<ValueNumber, ValueNumber> ValueNumberPair;
  222. typedef JsUtil::BaseDictionary<ValueNumberPair, Value *, JitArenaAllocator> ValueNumberPairToValueMap;
  223. namespace JsUtil
  224. {
  225. template <>
  226. class ValueEntry<StackLiteralInitFldData> : public BaseValueEntry<StackLiteralInitFldData>
  227. {
  228. public:
  229. void Clear()
  230. {
  231. #if DBG
  232. this->value.propIds = nullptr;
  233. this->value.currentInitFldCount = (uint)-1;
  234. #endif
  235. }
  236. };
  237. };
  238. typedef JsUtil::BaseDictionary<IntConstType, StackSym *, JitArenaAllocator> IntConstantToStackSymMap;
  239. typedef JsUtil::BaseDictionary<int32, Value *, JitArenaAllocator> IntConstantToValueMap;
  240. typedef JsUtil::BaseDictionary<int64, Value *, JitArenaAllocator> Int64ConstantToValueMap;
  241. typedef JsUtil::BaseDictionary<Js::Var, Value *, JitArenaAllocator> AddrConstantToValueMap;
  242. typedef JsUtil::BaseDictionary<Js::InternalString, Value *, JitArenaAllocator> StringConstantToValueMap;
  243. class JsArrayKills
  244. {
  245. private:
  246. union
  247. {
  248. struct
  249. {
  250. bool killsAllArrays : 1;
  251. bool killsArraysWithNoMissingValues : 1;
  252. bool killsNativeArrays : 1;
  253. bool killsArrayHeadSegments : 1;
  254. bool killsArrayHeadSegmentLengths : 1;
  255. bool killsArrayLengths : 1;
  256. };
  257. byte bits;
  258. };
  259. public:
  260. JsArrayKills() : bits(0)
  261. {
  262. }
  263. private:
  264. JsArrayKills(const byte bits) : bits(bits)
  265. {
  266. }
  267. public:
  268. bool KillsAllArrays() const { return killsAllArrays; }
  269. void SetKillsAllArrays() { killsAllArrays = true; }
  270. bool KillsArraysWithNoMissingValues() const { return killsArraysWithNoMissingValues; }
  271. void SetKillsArraysWithNoMissingValues() { killsArraysWithNoMissingValues = true; }
  272. bool KillsNativeArrays() const { return killsNativeArrays; }
  273. void SetKillsNativeArrays() { killsNativeArrays = true; }
  274. bool KillsArrayHeadSegments() const { return killsArrayHeadSegments; }
  275. void SetKillsArrayHeadSegments() { killsArrayHeadSegments = true; }
  276. bool KillsArrayHeadSegmentLengths() const { return killsArrayHeadSegmentLengths; }
  277. void SetKillsArrayHeadSegmentLengths() { killsArrayHeadSegmentLengths = true; }
  278. bool KillsTypedArrayHeadSegmentLengths() const { return KillsAllArrays(); }
  279. bool KillsArrayLengths() const { return killsArrayLengths; }
  280. void SetKillsArrayLengths() { killsArrayLengths = true; }
  281. public:
  282. bool KillsValueType(const ValueType valueType) const
  283. {
  284. Assert(valueType.IsArrayOrObjectWithArray());
  285. return
  286. killsAllArrays ||
  287. (killsArraysWithNoMissingValues && valueType.HasNoMissingValues()) ||
  288. (killsNativeArrays && !valueType.HasVarElements());
  289. }
  290. bool AreSubsetOf(const JsArrayKills &other) const
  291. {
  292. return (bits & other.bits) == bits;
  293. }
  294. JsArrayKills Merge(const JsArrayKills &other)
  295. {
  296. return bits | other.bits;
  297. }
  298. };
  299. class InvariantBlockBackwardIterator
  300. {
  301. private:
  302. GlobOpt *const globOpt;
  303. BasicBlock *const exclusiveEndBlock;
  304. StackSym *const invariantSym;
  305. const ValueNumber invariantSymValueNumber;
  306. BasicBlock *block;
  307. Value *invariantSymValue;
  308. #if DBG
  309. BasicBlock *const inclusiveEndBlock;
  310. #endif
  311. public:
  312. InvariantBlockBackwardIterator(GlobOpt *const globOpt, BasicBlock *const exclusiveBeginBlock, BasicBlock *const inclusiveEndBlock, StackSym *const invariantSym, const ValueNumber invariantSymValueNumber = InvalidValueNumber);
  313. public:
  314. bool IsValid() const;
  315. void MoveNext();
  316. BasicBlock *Block() const;
  317. Value *InvariantSymValue() const;
  318. PREVENT_ASSIGN(InvariantBlockBackwardIterator);
  319. };
  320. class FlowGraph;
  321. class GlobOpt
  322. {
  323. private:
  324. class AddSubConstantInfo;
  325. class ArrayLowerBoundCheckHoistInfo;
  326. class ArrayUpperBoundCheckHoistInfo;
  327. friend BackwardPass;
  328. #if DBG
  329. friend class ObjectTempVerify;
  330. #endif
  331. friend class GlobOptBlockData;
  332. friend class BasicBlock;
  333. private:
  334. SparseArray<Value> * byteCodeConstantValueArray;
  335. // Global bitvectors
  336. BVSparse<JitArenaAllocator> * byteCodeConstantValueNumbersBv;
  337. // Global bitvectors
  338. IntConstantToStackSymMap * intConstantToStackSymMap;
  339. IntConstantToValueMap* intConstantToValueMap;
  340. Int64ConstantToValueMap* int64ConstantToValueMap;
  341. AddrConstantToValueMap * addrConstantToValueMap;
  342. StringConstantToValueMap * stringConstantToValueMap;
  343. #if DBG
  344. // We can still track the finished stack literal InitFld lexically.
  345. BVSparse<JitArenaAllocator> * finishedStackLiteralInitFld;
  346. #endif
  347. BVSparse<JitArenaAllocator> * byteCodeUses;
  348. BVSparse<JitArenaAllocator> * tempBv; // Bit vector for temporary uses
  349. BVSparse<JitArenaAllocator> * objectTypeSyms;
  350. BVSparse<JitArenaAllocator> * prePassCopyPropSym; // Symbols that were copy prop'd during loop prepass
  351. PropertySym * propertySymUse;
  352. BVSparse<JitArenaAllocator> * lengthEquivBv;
  353. BVSparse<JitArenaAllocator> * argumentsEquivBv;
  354. BVSparse<JitArenaAllocator> * callerEquivBv;
  355. BVSparse<JitArenaAllocator> * changedSymsAfterIncBailoutCandidate;
  356. JitArenaAllocator * alloc;
  357. JitArenaAllocator * tempAlloc;
  358. Func * func;
  359. ValueNumber currentValue;
  360. BasicBlock * currentBlock;
  361. Region * currentRegion;
  362. IntOverflowDoesNotMatterRange *intOverflowDoesNotMatterRange;
  363. Loop * prePassLoop;
  364. Loop * rootLoopPrePass;
  365. uint instrCountSinceLastCleanUp;
  366. SymIdToInstrMap * prePassInstrMap;
  367. SymID maxInitialSymID;
  368. bool isCallHelper: 1;
  369. bool intOverflowCurrentlyMattersInRange : 1;
  370. bool ignoredIntOverflowForCurrentInstr : 1;
  371. bool ignoredNegativeZeroForCurrentInstr : 1;
  372. bool inInlinedBuiltIn : 1;
  373. bool isRecursiveCallOnLandingPad : 1;
  374. bool updateInductionVariableValueNumber : 1;
  375. bool isPerformingLoopBackEdgeCompensation : 1;
  376. bool doTypeSpec : 1;
  377. bool doAggressiveIntTypeSpec : 1;
  378. bool doAggressiveMulIntTypeSpec : 1;
  379. bool doDivIntTypeSpec : 1;
  380. bool doLossyIntTypeSpec : 1;
  381. bool doFloatTypeSpec : 1;
  382. bool doArrayCheckHoist : 1;
  383. bool doArrayMissingValueCheckHoist : 1;
  384. bool doArraySegmentHoist : 1;
  385. bool doJsArraySegmentHoist : 1;
  386. bool doArrayLengthHoist : 1;
  387. bool doEliminateArrayAccessHelperCall : 1;
  388. bool doTrackRelativeIntBounds : 1;
  389. bool doBoundCheckElimination : 1;
  390. bool doBoundCheckHoist : 1;
  391. bool doLoopCountBasedBoundCheckHoist : 1;
  392. bool doPowIntIntTypeSpec : 1;
  393. bool isAsmJSFunc : 1;
  394. bool doTagChecks : 1;
  395. OpndList * noImplicitCallUsesToInsert;
  396. ValueSetByValueNumber * valuesCreatedForClone;
  397. ValueNumberPairToValueMap *valuesCreatedForMerge;
  398. #if DBG
  399. BVSparse<JitArenaAllocator> * byteCodeUsesBeforeOpt;
  400. #endif
  401. public:
  402. GlobOpt(Func * func);
  403. void Optimize();
  404. // Function used by the backward pass as well.
  405. // GlobOptBailout.cpp
  406. static void TrackByteCodeSymUsed(IR::Instr * instr, BVSparse<JitArenaAllocator> * instrByteCodeStackSymUsed, PropertySym **pPropertySym);
  407. // GlobOptFields.cpp
  408. void ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt);
  409. static bool DoFieldHoisting(Loop * loop);
  410. IR::ByteCodeUsesInstr * ConvertToByteCodeUses(IR::Instr * isntr);
  411. bool GetIsAsmJSFunc()const{ return isAsmJSFunc; };
  412. private:
  413. bool IsLoopPrePass() const { return this->prePassLoop != nullptr; }
  414. void OptBlock(BasicBlock *block);
  415. void BackwardPass(Js::Phase tag);
  416. void ForwardPass();
  417. void OptLoops(Loop *loop);
  418. void TailDupPass();
  419. bool TryTailDup(IR::BranchInstr *tailBranch);
  420. PRECandidatesList * FindBackEdgePRECandidates(BasicBlock *block, JitArenaAllocator *alloc);
  421. PRECandidatesList * FindPossiblePRECandidates(Loop *loop, JitArenaAllocator *alloc);
  422. void PreloadPRECandidates(Loop *loop, PRECandidatesList *candidates);
  423. BOOL PreloadPRECandidate(Loop *loop, GlobHashBucket* candidate);
  424. void SetLoopFieldInitialValue(Loop *loop, IR::Instr *instr, PropertySym *propertySym, PropertySym *originalPropertySym);
  425. void FieldPRE(Loop *loop);
  426. void CloneBlockData(BasicBlock *const toBlock, BasicBlock *const fromBlock);
  427. void CloneValues(BasicBlock *const toBlock, GlobOptBlockData *toData, GlobOptBlockData *fromData);
  428. void TryReplaceLdLen(IR::Instr *& instr);
  429. IR::Instr * OptInstr(IR::Instr *&instr, bool* isInstrCleared);
  430. Value* OptDst(IR::Instr **pInstr, Value *dstVal, Value *src1Val, Value *src2Val, Value *dstIndirIndexVal, Value *src1IndirIndexVal);
  431. void CopyPropDstUses(IR::Opnd *opnd, IR::Instr *instr, Value *src1Val);
  432. Value * OptSrc(IR::Opnd *opnd, IR::Instr * *pInstr, Value **indirIndexValRef = nullptr, IR::IndirOpnd *parentIndirOpnd = nullptr);
  433. void MarkArgumentsUsedForBranch(IR::Instr *inst);
  434. bool OptTagChecks(IR::Instr *instr);
  435. void TryOptimizeInstrWithFixedDataProperty(IR::Instr * * const pInstr);
  436. bool CheckIfPropOpEmitsTypeCheck(IR::Instr *instr, IR::PropertySymOpnd *opnd);
  437. IR::PropertySymOpnd * CreateOpndForTypeCheckOnly(IR::PropertySymOpnd* opnd, Func* func);
  438. bool FinishOptPropOp(IR::Instr *instr, IR::PropertySymOpnd *opnd, BasicBlock* block = nullptr, bool updateExistingValue = false, bool* emitsTypeCheckOut = nullptr, bool* changesTypeValueOut = nullptr);
  439. void FinishOptHoistedPropOps(Loop * loop);
  440. IR::Instr * SetTypeCheckBailOut(IR::Opnd *opnd, IR::Instr *instr, BailOutInfo *bailOutInfo);
  441. void OptArguments(IR::Instr *Instr);
  442. void TrackInstrsForScopeObjectRemoval(IR::Instr * instr);
  443. bool AreFromSameBytecodeFunc(IR::RegOpnd const* src1, IR::RegOpnd const* dst) const;
  444. Value * ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val);
  445. Value * ValueNumberLdElemDst(IR::Instr **pInstr, Value *srcVal);
  446. ValueType GetPrepassValueTypeForDst(const ValueType desiredValueType, IR::Instr *const instr, Value *const src1Value, Value *const src2Value, bool *const isValueInfoPreciseRef = nullptr) const;
  447. bool IsPrepassSrcValueInfoPrecise(IR::Opnd *const src, Value *const srcValue) const;
  448. Value * CreateDstUntransferredIntValue(const int32 min, const int32 max, IR::Instr *const instr, Value *const src1Value, Value *const src2Value);
  449. Value * CreateDstUntransferredValue(const ValueType desiredValueType, IR::Instr *const instr, Value *const src1Value, Value *const src2Value);
  450. Value * ValueNumberTransferDst(IR::Instr *const instr, Value *src1Val);
  451. bool IsSafeToTransferInPrePass(IR::Opnd *src, Value *srcValue);
  452. Value * ValueNumberTransferDstInPrepass(IR::Instr *const instr, Value *const src1Val);
  453. IR::Opnd * CopyProp(IR::Opnd *opnd, IR::Instr *instr, Value *val, IR::IndirOpnd *parentIndirOpnd = nullptr);
  454. IR::Opnd * CopyPropReplaceOpnd(IR::Instr * instr, IR::Opnd * opnd, StackSym * copySym, IR::IndirOpnd *parentIndirOpnd = nullptr);
  455. ValueNumber NewValueNumber();
  456. Value * NewValue(ValueInfo *const valueInfo);
  457. Value * NewValue(const ValueNumber valueNumber, ValueInfo *const valueInfo);
  458. Value * CopyValue(Value const *const value);
  459. Value * CopyValue(Value const *const value, const ValueNumber valueNumber);
  460. Value * NewGenericValue(const ValueType valueType);
  461. Value * NewGenericValue(const ValueType valueType, IR::Opnd *const opnd);
  462. Value * NewGenericValue(const ValueType valueType, Sym *const sym);
  463. Value * GetIntConstantValue(const int32 intConst, IR::Instr * instr, IR::Opnd *const opnd = nullptr);
  464. Value * GetIntConstantValue(const int64 intConst, IR::Instr * instr, IR::Opnd *const opnd = nullptr);
  465. Value * NewIntConstantValue(const int32 intConst, IR::Instr * instr, bool isTaggable);
  466. Value * NewInt64ConstantValue(const int64 intConst, IR::Instr * instr);
  467. ValueInfo * NewIntRangeValueInfo(const int32 min, const int32 max, const bool wasNegativeZeroPreventedByBailout);
  468. ValueInfo * NewIntRangeValueInfo(const ValueInfo *const originalValueInfo, const int32 min, const int32 max) const;
  469. Value * NewIntRangeValue(const int32 min, const int32 max, const bool wasNegativeZeroPreventedByBailout, IR::Opnd *const opnd = nullptr);
  470. IntBoundedValueInfo * NewIntBoundedValueInfo(const ValueInfo *const originalValueInfo, const IntBounds *const bounds) const;
  471. Value * NewIntBoundedValue(const ValueType valueType, const IntBounds *const bounds, const bool wasNegativeZeroPreventedByBailout, IR::Opnd *const opnd = nullptr);
  472. Value * NewFloatConstantValue(const FloatConstType floatValue, IR::Opnd *const opnd = nullptr);
  473. Value * GetVarConstantValue(IR::AddrOpnd *addrOpnd);
  474. Value * NewVarConstantValue(IR::AddrOpnd *addrOpnd, bool isString);
  475. Value * HoistConstantLoadAndPropagateValueBackward(Js::Var varConst, IR::Instr * origInstr, Value * value);
  476. Value * NewFixedFunctionValue(Js::JavascriptFunction *functionValue, IR::AddrOpnd *addrOpnd);
  477. StackSym * GetTaggedIntConstantStackSym(const int32 intConstantValue) const;
  478. StackSym * GetOrCreateTaggedIntConstantStackSym(const int32 intConstantValue) const;
  479. Sym * SetSymStore(ValueInfo *valueInfo, Sym *sym);
  480. void SetSymStoreDirect(ValueInfo *valueInfo, Sym *sym);
  481. IR::Instr * TypeSpecialization(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val, Value **pDstVal, bool *redoTypeSpecRef, bool *const forceInvariantHoistingRef);
  482. #ifdef ENABLE_SIMDJS
  483. // SIMD_JS
  484. bool TypeSpecializeSimd128(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val, Value **pDstVal);
  485. bool Simd128DoTypeSpec(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal);
  486. bool Simd128DoTypeSpecLoadStore(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal, const ThreadContext::SimdFuncSignature *simdFuncSignature);
  487. bool Simd128CanTypeSpecOpnd(const ValueType opndType, const ValueType expectedType);
  488. bool Simd128ValidateIfLaneIndex(const IR::Instr * instr, IR::Opnd * opnd, uint argPos);
  489. void UpdateBoundCheckHoistInfoForSimd(ArrayUpperBoundCheckHoistInfo &upperHoistInfo, ValueType arrValueType, const IR::Instr *instr);
  490. void Simd128SetIndirOpndType(IR::IndirOpnd *indirOpnd, Js::OpCode opcode);
  491. #endif
  492. IRType GetIRTypeFromValueType(const ValueType &valueType);
  493. ValueType GetValueTypeFromIRType(const IRType &type);
  494. IR::BailOutKind GetBailOutKindFromValueType(const ValueType &valueType);
  495. IR::Instr * GetExtendedArg(IR::Instr *instr);
  496. int GetBoundCheckOffsetForSimd(ValueType arrValueType, const IR::Instr *instr, const int oldOffset = -1);
  497. IR::Instr * OptNewScObject(IR::Instr** instrPtr, Value* srcVal);
  498. template <typename T>
  499. bool OptConstFoldBinaryWasm(IR::Instr * *pInstr, const Value* src1, const Value* src2, Value **pDstVal);
  500. template <typename T>
  501. IR::Opnd* ReplaceWConst(IR::Instr **pInstr, T value, Value **pDstVal);
  502. bool OptConstFoldBinary(IR::Instr * *pInstr, const IntConstantBounds &src1IntConstantBounds, const IntConstantBounds &src2IntConstantBounds, Value **pDstVal);
  503. bool OptConstFoldUnary(IR::Instr * *pInstr, const int32 intConstantValue, const bool isUsingOriginalSrc1Value, Value **pDstVal);
  504. bool OptConstPeep(IR::Instr *instr, IR::Opnd *constSrc, Value **pDstVal, ValueInfo *vInfo);
  505. bool OptConstFoldBranch(IR::Instr *instr, Value *src1Val, Value*src2Val, Value **pDstVal);
  506. Js::Var GetConstantVar(IR::Opnd *opnd, Value *val);
  507. bool IsWorthSpecializingToInt32DueToSrc(IR::Opnd *const src, Value *const val);
  508. bool IsWorthSpecializingToInt32DueToDst(IR::Opnd *const dst);
  509. bool IsWorthSpecializingToInt32(IR::Instr *const instr, Value *const src1Val, Value *const src2Val = nullptr);
  510. bool TypeSpecializeNumberUnary(IR::Instr *instr, Value *src1Val, Value **pDstVal);
  511. bool TypeSpecializeIntUnary(IR::Instr **pInstr, Value **pSrc1Val, Value **pDstVal, int32 min, int32 max, Value *const src1OriginalVal, bool *redoTypeSpecRef, bool skipDst = false);
  512. bool TypeSpecializeIntBinary(IR::Instr **pInstr, Value *src1Val, Value *src2Val, Value **pDstVal, int32 min, int32 max, bool skipDst = false);
  513. void TypeSpecializeInlineBuiltInUnary(IR::Instr **pInstr, Value **pSrc1Val, Value **pDstVal, Value *const src1OriginalVal, bool *redoTypeSpecRef);
  514. void TypeSpecializeInlineBuiltInBinary(IR::Instr **pInstr, Value *src1Val, Value* src2Val, Value **pDstVal, Value *const src1OriginalVal, Value *const src2OriginalVal);
  515. void TypeSpecializeInlineBuiltInDst(IR::Instr **pInstr, Value **pDstVal);
  516. bool TypeSpecializeUnary(IR::Instr **pInstr, Value **pSrc1Val, Value **pDstVal, Value *const src1OriginalVal, bool *redoTypeSpecRef, bool *const forceInvariantHoistingRef);
  517. bool TypeSpecializeBinary(IR::Instr **pInstr, Value **pSrc1Val, Value **pSrc2Val, Value **pDstVal, Value *const src1OriginalVal, Value *const src2OriginalVal, bool *redoTypeSpecRef);
  518. bool TypeSpecializeFloatUnary(IR::Instr **pInstr, Value *src1Val, Value **pDstVal, bool skipDst = false);
  519. bool TypeSpecializeFloatBinary(IR::Instr *instr, Value *src1Val, Value *src2Val, Value **pDstVal);
  520. void TypeSpecializeFloatDst(IR::Instr *instr, Value *valToTransfer, Value *const src1Value, Value *const src2Value, Value **pDstVal);
  521. bool TypeSpecializeLdLen(IR::Instr * *const instrRef, Value * *const src1ValueRef, Value * *const dstValueRef, bool *const forceInvariantHoistingRef);
  522. void TypeSpecializeIntDst(IR::Instr* instr, Js::OpCode originalOpCode, Value* valToTransfer, Value *const src1Value, Value *const src2Value, const IR::BailOutKind bailOutKind, int32 newMin, int32 newMax, Value** pDstVal, const AddSubConstantInfo *const addSubConstantInfo = nullptr);
  523. void TypeSpecializeIntDst(IR::Instr* instr, Js::OpCode originalOpCode, Value* valToTransfer, Value *const src1Value, Value *const src2Value, const IR::BailOutKind bailOutKind, ValueType valueType, Value** pDstVal, const AddSubConstantInfo *const addSubConstantInfo = nullptr);
  524. void TypeSpecializeIntDst(IR::Instr* instr, Js::OpCode originalOpCode, Value* valToTransfer, Value *const src1Value, Value *const src2Value, const IR::BailOutKind bailOutKind, ValueType valueType, int32 newMin, int32 newMax, Value** pDstVal, const AddSubConstantInfo *const addSubConstantInfo = nullptr);
  525. bool TryTypeSpecializeUnaryToFloatHelper(IR::Instr** pInstr, Value** pSrc1Val, Value* const src1OriginalVal, Value **pDstVal);
  526. bool TypeSpecializeBailoutExpectedInteger(IR::Instr* instr, Value* src1Val, Value** dstVal);
  527. bool TypeSpecializeStElem(IR::Instr **pInstr, Value *src1Val, Value **pDstVal);
  528. bool ShouldExpectConventionalArrayIndexValue(IR::IndirOpnd *const indirOpnd);
  529. ValueType GetDivValueType(IR::Instr* instr, Value* src1Val, Value* src2Val, bool specialize);
  530. bool IsInstrInvalidForMemOp(IR::Instr *, Loop *, Value *, Value *);
  531. bool CollectMemOpInfo(IR::Instr *, IR::Instr *, Value *, Value *);
  532. bool CollectMemOpStElementI(IR::Instr *, Loop *);
  533. bool CollectMemsetStElementI(IR::Instr *, Loop *);
  534. bool CollectMemcopyStElementI(IR::Instr *, Loop *);
  535. bool CollectMemOpLdElementI(IR::Instr *, Loop *);
  536. bool CollectMemcopyLdElementI(IR::Instr *, Loop *);
  537. SymID GetVarSymID(StackSym *);
  538. const InductionVariable* GetInductionVariable(SymID, Loop *);
  539. bool IsSymIDInductionVariable(SymID, Loop *);
  540. bool IsAllowedForMemOpt(IR::Instr* instr, bool isMemset, IR::RegOpnd *baseOpnd, IR::Opnd *indexOpnd);
  541. void ProcessMemOp();
  542. bool InspectInstrForMemSetCandidate(Loop* loop, IR::Instr* instr, struct MemSetEmitData* emitData, bool& errorInInstr);
  543. bool InspectInstrForMemCopyCandidate(Loop* loop, IR::Instr* instr, struct MemCopyEmitData* emitData, bool& errorInInstr);
  544. bool ValidateMemOpCandidates(Loop * loop, _Out_writes_(iEmitData) struct MemOpEmitData** emitData, int& iEmitData);
  545. void EmitMemop(Loop * loop, LoopCount *loopCount, const struct MemOpEmitData* emitData);
  546. IR::Opnd* GenerateInductionVariableChangeForMemOp(Loop *loop, byte unroll, IR::Instr *insertBeforeInstr = nullptr);
  547. IR::RegOpnd* GenerateStartIndexOpndForMemop(Loop *loop, IR::Opnd *indexOpnd, IR::Opnd *sizeOpnd, bool isInductionVariableChangeIncremental, bool bIndexAlreadyChanged, IR::Instr *insertBeforeInstr = nullptr);
  548. LoopCount* GetOrGenerateLoopCountForMemOp(Loop *loop);
  549. IR::Instr* FindUpperBoundsCheckInstr(IR::Instr* instr);
  550. IR::Instr* FindArraySegmentLoadInstr(IR::Instr* instr);
  551. void RemoveMemOpSrcInstr(IR::Instr* memopInstr, IR::Instr* srcInstr, BasicBlock* block);
  552. void GetMemOpSrcInfo(Loop* loop, IR::Instr* instr, IR::RegOpnd*& base, IR::RegOpnd*& index, IRType& arrayType);
  553. bool HasMemOp(Loop * loop);
  554. private:
  555. void ChangeValueType(BasicBlock *const block, Value *const value, const ValueType newValueType, const bool preserveSubclassInfo, const bool allowIncompatibleType = false) const;
  556. void ChangeValueInfo(BasicBlock *const block, Value *const value, ValueInfo *const newValueInfo, const bool allowIncompatibleType = false, const bool compensated = false) const;
  557. bool AreValueInfosCompatible(const ValueInfo *const v0, const ValueInfo *const v1) const;
  558. private:
  559. #if DBG
  560. void VerifyArrayValueInfoForTracking(const ValueInfo *const valueInfo, const bool isJsArray, const BasicBlock *const block, const bool ignoreKnownImplicitCalls = false) const;
  561. #endif
  562. void TrackNewValueForKills(Value *const value);
  563. void DoTrackNewValueForKills(Value *const value);
  564. void TrackCopiedValueForKills(Value *const value);
  565. void DoTrackCopiedValueForKills(Value *const value);
  566. void TrackMergedValueForKills(Value *const value, GlobOptBlockData *const blockData, BVSparse<JitArenaAllocator> *const mergedValueTypesTrackedForKills) const;
  567. void DoTrackMergedValueForKills(Value *const value, GlobOptBlockData *const blockData, BVSparse<JitArenaAllocator> *const mergedValueTypesTrackedForKills) const;
  568. void TrackValueInfoChangeForKills(BasicBlock *const block, Value *const value, ValueInfo *const newValueInfo, const bool compensated) const;
  569. void ProcessValueKills(IR::Instr *const instr);
  570. void ProcessValueKills(BasicBlock *const block, GlobOptBlockData *const blockData);
  571. void ProcessValueKillsForLoopHeaderAfterBackEdgeMerge(BasicBlock *const block, GlobOptBlockData *const blockData);
  572. bool NeedBailOnImplicitCallForLiveValues(BasicBlock const * const block, const bool isForwardPass) const;
  573. IR::Instr* CreateBoundsCheckInstr(IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset, Func* func);
  574. IR::Instr* CreateBoundsCheckInstr(IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset, IR::BailOutKind bailoutkind, BailOutInfo* bailoutInfo, Func* func);
  575. IR::Instr* AttachBoundsCheckData(IR::Instr* instr, IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset);
  576. void OptArraySrc(IR::Instr * *const instrRef);
  577. private:
  578. void TrackIntSpecializedAddSubConstant(IR::Instr *const instr, const AddSubConstantInfo *const addSubConstantInfo, Value *const dstValue, const bool updateSourceBounds);
  579. void CloneBoundCheckHoistBlockData(BasicBlock *const toBlock, GlobOptBlockData *const toData, BasicBlock *const fromBlock, GlobOptBlockData *const fromData);
  580. void MergeBoundCheckHoistBlockData(BasicBlock *const toBlock, GlobOptBlockData *const toData, BasicBlock *const fromBlock, GlobOptBlockData *const fromData);
  581. void DetectUnknownChangesToInductionVariables(GlobOptBlockData *const blockData);
  582. void SetInductionVariableValueNumbers(GlobOptBlockData *const blockData);
  583. void FinalizeInductionVariables(Loop *const loop, GlobOptBlockData *const headerData);
  584. enum class SymBoundType {OFFSET, VALUE, UNKNOWN};
  585. SymBoundType DetermineSymBoundOffsetOrValueRelativeToLandingPad(StackSym *const sym, const bool landingPadValueIsLowerBound, ValueInfo *const valueInfo, const IntBounds *const bounds, GlobOptBlockData *const landingPadGlobOptBlockData, int *const boundOffsetOrValueRef);
  586. private:
  587. void DetermineDominatingLoopCountableBlock(Loop *const loop, BasicBlock *const headerBlock);
  588. void DetermineLoopCount(Loop *const loop);
  589. void GenerateLoopCount(Loop *const loop, LoopCount *const loopCount);
  590. void GenerateLoopCountPlusOne(Loop *const loop, LoopCount *const loopCount);
  591. void GenerateSecondaryInductionVariableBound(Loop *const loop, StackSym *const inductionVariableSym, const LoopCount *const loopCount, const int maxMagnitudeChange, StackSym *const boundSym);
  592. private:
  593. void DetermineArrayBoundCheckHoistability(bool needLowerBoundCheck, bool needUpperBoundCheck, ArrayLowerBoundCheckHoistInfo &lowerHoistInfo, ArrayUpperBoundCheckHoistInfo &upperHoistInfo, const bool isJsArray, StackSym *const indexSym, Value *const indexValue, const IntConstantBounds &indexConstantBounds, StackSym *const headSegmentLengthSym, Value *const headSegmentLengthValue, const IntConstantBounds &headSegmentLengthConstantBounds, Loop *const headSegmentLengthInvariantLoop, bool &failedToUpdateCompatibleLowerBoundCheck, bool &failedToUpdateCompatibleUpperBoundCheck);
  594. private:
  595. void CaptureNoImplicitCallUses(IR::Opnd *opnd, const bool usesNoMissingValuesInfo, IR::Instr *const includeCurrentInstr = nullptr);
  596. void InsertNoImplicitCallUses(IR::Instr *const instr);
  597. void PrepareLoopArrayCheckHoist();
  598. public:
  599. JsArrayKills CheckJsArrayKills(IR::Instr *const instr);
  600. GlobOptBlockData const * CurrentBlockData() const;
  601. GlobOptBlockData * CurrentBlockData();
  602. private:
  603. bool IsOperationThatLikelyKillsJsArraysWithNoMissingValues(IR::Instr *const instr);
  604. bool NeedBailOnImplicitCallForArrayCheckHoist(BasicBlock const * const block, const bool isForwardPass) const;
  605. private:
  606. bool PrepareForIgnoringIntOverflow(IR::Instr *const instr);
  607. void VerifyIntSpecForIgnoringIntOverflow(IR::Instr *const instr);
  608. void PreLowerCanonicalize(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val);
  609. void ProcessKills(IR::Instr *instr);
  610. void InsertCloneStrs(BasicBlock *toBlock, GlobOptBlockData *toData, GlobOptBlockData *fromData);
  611. void InsertValueCompensation(BasicBlock *const predecessor, const SymToValueInfoMap &symsRequiringCompensationToMergedValueInfoMap);
  612. IR::Instr * ToVarUses(IR::Instr *instr, IR::Opnd *opnd, bool isDst, Value *val);
  613. void ToVar(BVSparse<JitArenaAllocator> *bv, BasicBlock *block);
  614. IR::Instr * ToVar(IR::Instr *instr, IR::RegOpnd *regOpnd, BasicBlock *block, Value *val, bool needsUpdate);
  615. void ToInt32(BVSparse<JitArenaAllocator> *bv, BasicBlock *block, bool lossy, IR::Instr *insertBeforeInstr = nullptr);
  616. void ToFloat64(BVSparse<JitArenaAllocator> *bv, BasicBlock *block);
  617. void ToTypeSpec(BVSparse<JitArenaAllocator> *bv, BasicBlock *block, IRType toType, IR::BailOutKind bailOutKind = IR::BailOutInvalid, bool lossy = false, IR::Instr *insertBeforeInstr = nullptr);
  618. IR::Instr * ToInt32(IR::Instr *instr, IR::Opnd *opnd, BasicBlock *block, Value *val, IR::IndirOpnd *indir, bool lossy);
  619. IR::Instr * ToFloat64(IR::Instr *instr, IR::Opnd *opnd, BasicBlock *block, Value *val, IR::IndirOpnd *indir, IR::BailOutKind bailOutKind);
  620. IR::Instr * ToTypeSpecUse(IR::Instr *instr, IR::Opnd *opnd, BasicBlock *block, Value *val, IR::IndirOpnd *indir,
  621. IRType toType, IR::BailOutKind bailOutKind, bool lossy = false, IR::Instr *insertBeforeInstr = nullptr);
  622. void ToVarRegOpnd(IR::RegOpnd *dst, BasicBlock *block);
  623. void ToVarStackSym(StackSym *varSym, BasicBlock *block);
  624. void ToInt32Dst(IR::Instr *instr, IR::RegOpnd *dst, BasicBlock *block);
  625. void ToUInt32Dst(IR::Instr *instr, IR::RegOpnd *dst, BasicBlock *block);
  626. void ToFloat64Dst(IR::Instr *instr, IR::RegOpnd *dst, BasicBlock *block);
  627. #ifdef ENABLE_SIMDJS
  628. // SIMD_JS
  629. void TypeSpecializeSimd128Dst(IRType type, IR::Instr *instr, Value *valToTransfer, Value *const src1Value, Value **pDstVal);
  630. void ToSimd128Dst(IRType toType, IR::Instr *instr, IR::RegOpnd *dst, BasicBlock *block);
  631. #endif
  632. void OptConstFoldBr(bool test, IR::Instr *instr, Value * intTypeSpecSrc1Val = nullptr, Value * intTypeSpecSrc2Val = nullptr);
  633. void PropagateIntRangeForNot(int32 minimum, int32 maximum, int32 *pNewMin, int32 * pNewMax);
  634. void PropagateIntRangeBinary(IR::Instr *instr, int32 min1, int32 max1,
  635. int32 min2, int32 max2, int32 *pNewMin, int32 *pNewMax);
  636. bool OptIsInvariant(IR::Opnd *src, BasicBlock *block, Loop *loop, Value *srcVal, bool isNotTypeSpecConv, bool allowNonPrimitives);
  637. bool OptIsInvariant(Sym *sym, BasicBlock *block, Loop *loop, Value *srcVal, bool isNotTypeSpecConv, bool allowNonPrimitives, Value **loopHeadValRef = nullptr);
  638. bool OptDstIsInvariant(IR::RegOpnd *dst);
  639. bool OptIsInvariant(IR::Instr *instr, BasicBlock *block, Loop *loop, Value *src1Val, Value *src2Val, bool isNotTypeSpecConv, const bool forceInvariantHoisting = false);
  640. void OptHoistInvariant(IR::Instr *instr, BasicBlock *block, Loop *loop, Value *dstVal, Value *const src1Val, Value *const src2Value,
  641. bool isNotTypeSpecConv, bool lossy = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
  642. bool TryHoistInvariant(IR::Instr *instr, BasicBlock *block, Value *dstVal, Value *src1Val, Value *src2Val, bool isNotTypeSpecConv,
  643. const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
  644. void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
  645. void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd* srcOpnd, Value *const srcVal);
  646. public:
  647. static bool IsTypeSpecPhaseOff(Func const * func);
  648. static bool DoAggressiveIntTypeSpec(Func const * func);
  649. static bool DoLossyIntTypeSpec(Func const * func);
  650. static bool DoFloatTypeSpec(Func const * func);
  651. static bool DoStringTypeSpec(Func const * func);
  652. static bool DoArrayCheckHoist(Func const * const func);
  653. static bool DoArrayMissingValueCheckHoist(Func const * const func);
  654. static bool DoArraySegmentHoist(const ValueType baseValueType, Func const * const func);
  655. static bool DoArrayLengthHoist(Func const * const func);
  656. static bool DoEliminateArrayAccessHelperCall(Func* func);
  657. static bool DoTypedArrayTypeSpec(Func const * func);
  658. static bool DoNativeArrayTypeSpec(Func const * func);
  659. static bool IsSwitchOptEnabled(Func const * func);
  660. static bool DoInlineArgsOpt(Func const * func);
  661. static bool IsPREInstrCandidateLoad(Js::OpCode opcode);
  662. static bool IsPREInstrCandidateStore(Js::OpCode opcode);
  663. static bool ImplicitCallFlagsAllowOpts(Loop * loop);
  664. static bool ImplicitCallFlagsAllowOpts(Func const * func);
  665. private:
  666. bool DoConstFold() const;
  667. bool DoTypeSpec() const;
  668. bool DoAggressiveIntTypeSpec() const;
  669. bool DoAggressiveMulIntTypeSpec() const;
  670. bool DoDivIntTypeSpec() const;
  671. bool DoLossyIntTypeSpec() const;
  672. bool DoFloatTypeSpec() const;
  673. bool DoStringTypeSpec() const { return GlobOpt::DoStringTypeSpec(this->func); }
  674. bool DoArrayCheckHoist() const;
  675. bool DoArrayCheckHoist(const ValueType baseValueType, Loop* loop, IR::Instr const * const instr = nullptr) const;
  676. bool DoArrayMissingValueCheckHoist() const;
  677. bool DoArraySegmentHoist(const ValueType baseValueType) const;
  678. bool DoTypedArraySegmentLengthHoist(Loop *const loop) const;
  679. bool DoArrayLengthHoist() const;
  680. bool DoEliminateArrayAccessHelperCall() const;
  681. bool DoTypedArrayTypeSpec() const { return GlobOpt::DoTypedArrayTypeSpec(this->func); }
  682. bool DoNativeArrayTypeSpec() const { return GlobOpt::DoNativeArrayTypeSpec(this->func); }
  683. bool DoLdLenIntSpec(IR::Instr * const instr, const ValueType baseValueType);
  684. bool IsSwitchOptEnabled() const { return GlobOpt::IsSwitchOptEnabled(this->func); }
  685. bool DoPathDependentValues() const;
  686. bool DoTrackRelativeIntBounds() const;
  687. bool DoBoundCheckElimination() const;
  688. bool DoBoundCheckHoist() const;
  689. bool DoLoopCountBasedBoundCheckHoist() const;
  690. bool DoPowIntIntTypeSpec() const;
  691. bool DoTagChecks() const;
  692. private:
  693. // GlobOptBailout.cpp
  694. bool MayNeedBailOut(Loop * loop) const;
  695. static void TrackByteCodeSymUsed(IR::Opnd * opnd, BVSparse<JitArenaAllocator> * instrByteCodeStackSymUsed, PropertySym **pPropertySymUse);
  696. static void TrackByteCodeSymUsed(IR::RegOpnd * opnd, BVSparse<JitArenaAllocator> * instrByteCodeStackSymUsed);
  697. static void TrackByteCodeSymUsed(StackSym * sym, BVSparse<JitArenaAllocator> * instrByteCodeStackSymUsed);
  698. void CaptureValues(BasicBlock *block, BailOutInfo * bailOutInfo);
  699. void CaptureValuesFromScratch(
  700. BasicBlock * block,
  701. SListBase<ConstantStackSymValue>::EditingIterator & bailOutConstValuesIter,
  702. SListBase<CopyPropSyms>::EditingIterator & bailOutCopyPropIter);
  703. void CaptureValuesIncremental(
  704. BasicBlock * block,
  705. SListBase<ConstantStackSymValue>::EditingIterator & bailOutConstValuesIter,
  706. SListBase<CopyPropSyms>::EditingIterator & bailOutCopyPropIter);
  707. void CaptureCopyPropValue(BasicBlock * block, Sym * sym, Value * val, SListBase<CopyPropSyms>::EditingIterator & bailOutCopySymsIter);
  708. void CaptureArguments(BasicBlock *block, BailOutInfo * bailOutInfo, JitArenaAllocator *allocator);
  709. void CaptureByteCodeSymUses(IR::Instr * instr);
  710. IR::ByteCodeUsesInstr * InsertByteCodeUses(IR::Instr * instr, bool includeDef = false);
  711. void TrackCalls(IR::Instr * instr);
  712. void RecordInlineeFrameInfo(IR::Instr* instr);
  713. void EndTrackCall(IR::Instr * instr);
  714. void EndTrackingOfArgObjSymsForInlinee();
  715. void FillBailOutInfo(BasicBlock *block, BailOutInfo *bailOutInfo);
  716. static void MarkNonByteCodeUsed(IR::Instr * instr);
  717. static void MarkNonByteCodeUsed(IR::Opnd * opnd);
  718. bool IsImplicitCallBailOutCurrentlyNeeded(IR::Instr * instr, Value const * src1Val, Value const * src2Val) const;
  719. bool IsImplicitCallBailOutCurrentlyNeeded(IR::Instr * instr, Value const * src1Val, Value const * src2Val, BasicBlock const * block, bool hasLiveFields, bool mayNeedImplicitCallBailOut, bool isForwardPass) const;
  720. static bool IsTypeCheckProtected(const IR::Instr * instr);
  721. static bool MayNeedBailOnImplicitCall(IR::Instr const * instr, Value const * src1Val, Value const * src2Val);
  722. static bool MaySrcNeedBailOnImplicitCall(IR::Opnd const * opnd, Value const * val);
  723. void GenerateBailAfterOperation(IR::Instr * *const pInstr, IR::BailOutKind kind);
  724. public:
  725. void GenerateBailAtOperation(IR::Instr * *const pInstr, const IR::BailOutKind bailOutKind);
  726. private:
  727. IR::Instr * EnsureBailTarget(Loop * loop);
  728. // GlobOptFields.cpp
  729. void ProcessFieldKills(IR::Instr * instr);
  730. void KillLiveFields(StackSym * stackSym, BVSparse<JitArenaAllocator> * bv);
  731. void KillLiveFields(PropertySym * propertySym, BVSparse<JitArenaAllocator> * bv);
  732. void KillLiveFields(BVSparse<JitArenaAllocator> *const propertyEquivSet, BVSparse<JitArenaAllocator> *const bv) const;
  733. void KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
  734. void KillAllFields(BVSparse<JitArenaAllocator> * bv);
  735. void SetAnyPropertyMayBeWrittenTo();
  736. void AddToPropertiesWrittenTo(Js::PropertyId propertyId);
  737. bool DoFieldCopyProp() const;
  738. bool DoFieldCopyProp(Loop * loop) const;
  739. bool DoFunctionFieldCopyProp() const;
  740. bool DoFieldHoisting() const;
  741. bool DoObjTypeSpec() const;
  742. bool DoObjTypeSpec(Loop * loop) const;
  743. bool DoFieldRefOpts() const { return DoObjTypeSpec(); }
  744. bool DoFieldRefOpts(Loop * loop) const { return DoObjTypeSpec(loop); }
  745. bool DoFieldOpts(Loop * loop) const;
  746. bool DoFieldPRE() const;
  747. bool DoFieldPRE(Loop *loop) const;
  748. bool FieldHoistOptSrc(IR::Opnd *opnd, IR::Instr *instr, PropertySym * propertySym);
  749. void FieldHoistOptDst(IR::Instr * instr, PropertySym * propertySym, Value * src1Val);
  750. bool TrackHoistableFields() const;
  751. void PreparePrepassFieldHoisting(Loop * loop);
  752. void PrepareFieldHoisting(Loop * loop);
  753. void CheckFieldHoistCandidate(IR::Instr * instr, PropertySym * sym);
  754. Loop * FindFieldHoistStackSym(Loop * startLoop, SymID propertySymId, StackSym ** copySym, IR::Instr * instrToHoist = nullptr) const;
  755. bool CopyPropHoistedFields(PropertySym * sym, IR::Opnd ** ppOpnd, IR::Instr * instr);
  756. void HoistFieldLoad(PropertySym * sym, Loop * loop, IR::Instr * instr, Value * oldValue, Value * newValue);
  757. void HoistNewFieldLoad(PropertySym * sym, Loop * loop, IR::Instr * instr, Value * oldValue, Value * newValue);
  758. void GenerateHoistFieldLoad(PropertySym * sym, Loop * loop, IR::Instr * instr, StackSym * newStackSym, Value * oldValue, Value * newValue);
  759. void HoistFieldLoadValue(Loop * loop, Value * newValue, SymID symId, Js::OpCode opcode, IR::Opnd * srcOpnd);
  760. void ReloadFieldHoistStackSym(IR::Instr * instr, PropertySym * propertySym);
  761. void CopyStoreFieldHoistStackSym(IR::Instr * storeFldInstr, PropertySym * sym, Value * src1Val);
  762. Value * CreateFieldSrcValue(PropertySym * sym, PropertySym * originalSym, IR::Opnd **ppOpnd, IR::Instr * instr);
  763. static bool HasHoistableFields(BasicBlock const * block);
  764. static bool HasHoistableFields(GlobOptBlockData const * globOptData);
  765. bool IsHoistablePropertySym(SymID symId) const;
  766. bool NeedBailOnImplicitCallWithFieldOpts(Loop *loop, bool hasLiveFields) const;
  767. IR::Instr * EnsureDisableImplicitCallRegion(Loop * loop);
  768. void UpdateObjPtrValueType(IR::Opnd * opnd, IR::Instr * instr);
  769. bool TrackArgumentsObject();
  770. void CannotAllocateArgumentsObjectOnStack();
  771. #if DBG
  772. bool IsPropertySymId(SymID symId) const;
  773. bool IsHoistedPropertySym(PropertySym * sym) const;
  774. bool IsHoistedPropertySym(SymID symId, Loop * loop) const;
  775. static void AssertCanCopyPropOrCSEFieldLoad(IR::Instr * instr);
  776. #endif
  777. StackSym * EnsureObjectTypeSym(StackSym * objectSym);
  778. PropertySym * EnsurePropertyWriteGuardSym(PropertySym * propertySym);
  779. void PreparePropertySymForTypeCheckSeq(PropertySym *propertySym);
  780. bool IsPropertySymPreparedForTypeCheckSeq(PropertySym *propertySym);
  781. bool PreparePropertySymOpndForTypeCheckSeq(IR::PropertySymOpnd *propertySymOpnd, IR::Instr * instr, Loop *loop);
  782. static bool AreTypeSetsIdentical(Js::EquivalentTypeSet * leftTypeSet, Js::EquivalentTypeSet * rightTypeSet);
  783. static bool IsSubsetOf(Js::EquivalentTypeSet * leftTypeSet, Js::EquivalentTypeSet * rightTypeSet);
  784. static bool CompareCurrentTypesWithExpectedTypes(JsTypeValueInfo *valueInfo, IR::PropertySymOpnd * propertySymOpnd);
  785. bool ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd);
  786. bool CheckIfInstrInTypeCheckSeqEmitsTypeCheck(IR::Instr* instr, IR::PropertySymOpnd *opnd);
  787. template<bool makeChanges>
  788. bool ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd, BasicBlock* block, bool updateExistingValue, bool* emitsTypeCheckOut = nullptr, bool* changesTypeValueOut = nullptr, bool *isObjTypeChecked = nullptr);
  789. void KillObjectHeaderInlinedTypeSyms(BasicBlock *block, bool isObjTypeSpecialized, SymID symId = (SymID)-1);
  790. void ValueNumberObjectType(IR::Opnd *dstOpnd, IR::Instr *instr);
  791. void SetSingleTypeOnObjectTypeValue(Value* value, const JITTypeHolder type);
  792. void SetTypeSetOnObjectTypeValue(Value* value, Js::EquivalentTypeSet* typeSet);
  793. void UpdateObjectTypeValue(Value* value, const JITTypeHolder type, bool setType, Js::EquivalentTypeSet* typeSet, bool setTypeSet);
  794. void SetObjectTypeFromTypeSym(StackSym *typeSym, Value* value, BasicBlock* block = nullptr);
  795. void SetObjectTypeFromTypeSym(StackSym *typeSym, const JITTypeHolder type, Js::EquivalentTypeSet * typeSet, BasicBlock* block = nullptr, bool updateExistingValue = false);
  796. void SetObjectTypeFromTypeSym(StackSym *typeSym, const JITTypeHolder type, Js::EquivalentTypeSet * typeSet, GlobOptBlockData *blockData, bool updateExistingValue = false);
  797. void KillObjectType(StackSym *objectSym, BVSparse<JitArenaAllocator>* liveFields = nullptr);
  798. void KillAllObjectTypes(BVSparse<JitArenaAllocator>* liveFields = nullptr);
  799. void EndFieldLifetime(IR::SymOpnd *symOpnd);
  800. PropertySym * CopyPropPropertySymObj(IR::SymOpnd *opnd, IR::Instr *instr);
  801. static bool NeedsTypeCheckBailOut(const IR::Instr *instr, IR::PropertySymOpnd *propertySymOpnd, bool isStore, bool* pIsTypeCheckProtected, IR::BailOutKind *pBailOutKind);
  802. IR::Instr * PreOptPeep(IR::Instr *instr);
  803. IR::Instr * OptPeep(IR::Instr *instr, Value *src1Val, Value *src2Val);
  804. void OptimizeIndirUses(IR::IndirOpnd *indir, IR::Instr * *pInstr, Value **indirIndexValRef);
  805. void RemoveCodeAfterNoFallthroughInstr(IR::Instr *instr);
  806. void ProcessTryHandler(IR::Instr* instr);
  807. bool ProcessExceptionHandlingEdges(IR::Instr* instr);
  808. void InsertToVarAtDefInTryRegion(IR::Instr * instr, IR::Opnd * dstOpnd);
  809. void RemoveFlowEdgeToCatchBlock(IR::Instr * instr);
  810. bool RemoveFlowEdgeToFinallyOnExceptionBlock(IR::Instr * instr);
  811. void CSEAddInstr(BasicBlock *block, IR::Instr *instr, Value *dstVal, Value *src1Val, Value *src2Val, Value *dstIndirIndexVal, Value *src1IndirIndexVal);
  812. void OptimizeChecks(IR::Instr * const instr);
  813. bool CSEOptimize(BasicBlock *block, IR::Instr * *const instrRef, Value **pSrc1Val, Value **pSrc2Val, Value **pSrc1IndirIndexVal, bool intMathExprOnly = false);
  814. bool GetHash(IR::Instr *instr, Value *src1Val, Value *src2Val, ExprAttributes exprAttributes, ExprHash *pHash);
  815. void ProcessArrayValueKills(IR::Instr *instr);
  816. static bool NeedBailOnImplicitCallForCSE(BasicBlock const *block, bool isForwardPass);
  817. bool DoCSE();
  818. bool CanCSEArrayStore(IR::Instr *instr);
  819. #if DBG_DUMP
  820. void Dump() const;
  821. void DumpSymToValueMap() const;
  822. void DumpSymToValueMap(BasicBlock const * block) const;
  823. void DumpSymVal(int index);
  824. void Trace(BasicBlock * basicBlock, bool before) const;
  825. void TraceSettings() const;
  826. #endif
  827. bool IsWorthSpecializingToInt32Branch(IR::Instr const * instr, Value const * src1Val, Value const * src2Val) const;
  828. bool TryOptConstFoldBrFalse(IR::Instr *const instr, Value *const srcValue, const int32 min, const int32 max);
  829. bool TryOptConstFoldBrEqual(IR::Instr *const instr, const bool branchOnEqual, Value *const src1Value, const int32 min1, const int32 max1, Value *const src2Value, const int32 min2, const int32 max2);
  830. bool TryOptConstFoldBrGreaterThan(IR::Instr *const instr, const bool branchOnGreaterThan, Value *const src1Value, const int32 min1, const int32 max1, Value *const src2Value, const int32 min2, const int32 max2);
  831. bool TryOptConstFoldBrGreaterThanOrEqual(IR::Instr *const instr, const bool branchOnGreaterThanOrEqual, Value *const src1Value, const int32 min1, const int32 max1, Value *const src2Value, const int32 min2, const int32 max2);
  832. bool TryOptConstFoldBrUnsignedLessThan(IR::Instr *const instr, const bool branchOnLessThan, Value *const src1Value, const int32 min1, const int32 max1, Value *const src2Value, const int32 min2, const int32 max2);
  833. bool TryOptConstFoldBrUnsignedGreaterThan(IR::Instr *const instr, const bool branchOnGreaterThan, Value *const src1Value, const int32 min1, const int32 max1, Value *const src2Value, const int32 min2, const int32 max2);
  834. void UpdateIntBoundsForEqualBranch(Value *const src1Value, Value *const src2Value, const int32 src2ConstantValue = 0);
  835. void UpdateIntBoundsForNotEqualBranch(Value *const src1Value, Value *const src2Value, const int32 src2ConstantValue = 0);
  836. void UpdateIntBoundsForGreaterThanOrEqualBranch(Value *const src1Value, Value *const src2Value);
  837. void UpdateIntBoundsForGreaterThanBranch(Value *const src1Value, Value *const src2Value);
  838. void UpdateIntBoundsForLessThanOrEqualBranch(Value *const src1Value, Value *const src2Value);
  839. void UpdateIntBoundsForLessThanBranch(Value *const src1Value, Value *const src2Value);
  840. IntBounds * GetIntBoundsToUpdate(const ValueInfo *const valueInfo, const IntConstantBounds &constantBounds, const bool isSettingNewBound, const bool isBoundConstant, const bool isSettingUpperBound, const bool isExplicit);
  841. ValueInfo * UpdateIntBoundsForEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  842. ValueInfo * UpdateIntBoundsForNotEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  843. ValueInfo * UpdateIntBoundsForGreaterThanOrEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  844. ValueInfo * UpdateIntBoundsForGreaterThanOrEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const int boundOffset, const bool isExplicit);
  845. ValueInfo * UpdateIntBoundsForGreaterThan(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  846. ValueInfo * UpdateIntBoundsForLessThanOrEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  847. ValueInfo * UpdateIntBoundsForLessThanOrEqual(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const int boundOffset, const bool isExplicit);
  848. ValueInfo * UpdateIntBoundsForLessThan(Value *const value, const IntConstantBounds &constantBounds, Value *const boundValue, const IntConstantBounds &boundConstantBounds, const bool isExplicit);
  849. void SetPathDependentInfo(const bool conditionToBranch, const PathDependentInfo &info);
  850. PathDependentInfoToRestore UpdatePathDependentInfo(PathDependentInfo *const info);
  851. void RestorePathDependentInfo(PathDependentInfo *const info, const PathDependentInfoToRestore infoToRestore);
  852. IR::Instr * TrackMarkTempObject(IR::Instr * instrStart, IR::Instr * instrEnd);
  853. void TrackTempObjectSyms(IR::Instr * instr, IR::RegOpnd * opnd);
  854. IR::Instr * GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opnd, bool isDst);
  855. friend class InvariantBlockBackwardIterator;
  856. };