SimpleLayout.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. #include "BackEnd.h"
  6. IR::Instr *
  7. SimpleLayout::MoveHelperBlock(IR::Instr * lastOpHelperLabel, uint32 lastOpHelperStatementIndex, Func* lastOpHelperFunc, IR::LabelInstr * nextLabel,
  8. IR::Instr * instrAfter)
  9. {
  10. // Add pragma instructions around the moved code to track source mapping
  11. Func* pragmatInstrFunc = lastOpHelperFunc ? lastOpHelperFunc : this->func;
  12. if (instrAfter->IsPragmaInstr() && instrAfter->m_opcode == Js::OpCode::StatementBoundary)
  13. {
  14. IR::PragmaInstr* pragmaInstr = instrAfter->AsPragmaInstr();
  15. pragmaInstr->m_statementIndex = lastOpHelperStatementIndex;
  16. pragmaInstr->m_func = pragmatInstrFunc;
  17. }
  18. else
  19. {
  20. IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, lastOpHelperStatementIndex, pragmatInstrFunc);
  21. instrAfter->InsertAfter(pragmaInstr);
  22. instrAfter = pragmaInstr;
  23. }
  24. // Move all the instruction between lastOpHelperLabel to lastOpHelperInstr
  25. // to the end of the function
  26. IR::Instr * lastOpHelperInstr = nextLabel->GetPrevRealInstrOrLabel();
  27. IR::Instr::MoveRangeAfter(lastOpHelperLabel, lastOpHelperInstr, instrAfter);
  28. instrAfter = lastOpHelperInstr;
  29. // Add the jmp back if the lastOpHelperInstr has fall through
  30. if (instrAfter->HasFallThrough())
  31. {
  32. IR::BranchInstr * branchInstr = IR::BranchInstr::New(
  33. LowererMD::MDUncondBranchOpcode, nextLabel, this->func);
  34. instrAfter->InsertAfter(branchInstr);
  35. instrAfter = branchInstr;
  36. }
  37. // Add pragma terminating this source mapping range
  38. IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, Js::Constants::NoStatementIndex, this->func);
  39. instrAfter->InsertAfter(pragmaInstr);
  40. instrAfter = pragmaInstr;
  41. return instrAfter;
  42. }
  43. void
  44. SimpleLayout::Layout()
  45. {
  46. if (PHASE_OFF(Js::LayoutPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag))
  47. {
  48. return;
  49. }
  50. // Do simple layout of helper block. Push them to after FunctionExit.
  51. IR::Instr * lastInstr = func->m_tailInstr;
  52. IR::LabelInstr * lastOpHelperLabel = NULL;
  53. uint32 lastOpHelperStatementIndex = Js::Constants::NoStatementIndex;
  54. Func* lastOpHelperFunc = nullptr;
  55. FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, func->m_headInstr, func->m_tailInstr->m_prev)
  56. {
  57. if (instr->IsPragmaInstr() && instr->m_opcode == Js::OpCode::StatementBoundary)
  58. {
  59. currentStatement = instr->AsPragmaInstr();
  60. }
  61. else if (instr->IsLabelInstr())
  62. {
  63. IR::LabelInstr * labelInstr = instr->AsLabelInstr();
  64. if (labelInstr->isOpHelper)
  65. {
  66. if (lastOpHelperLabel == NULL)
  67. {
  68. lastOpHelperLabel = labelInstr;
  69. lastOpHelperStatementIndex = currentStatement ? currentStatement->m_statementIndex : Js::Constants::NoStatementIndex;
  70. lastOpHelperFunc = currentStatement ? currentStatement->m_func : nullptr;
  71. }
  72. }
  73. else if (lastOpHelperLabel != NULL)
  74. {
  75. IR::Instr * prevInstr = lastOpHelperLabel->GetPrevRealInstrOrLabel();
  76. if (prevInstr->IsBranchInstr())
  77. {
  78. // If the previous instruction is to jump around this helper block
  79. // Then we move the helper block to the end of the function to
  80. // avoid the jmp in the fast path.
  81. // jxx $label <== prevInstr
  82. // $helper: <== lastOpHelperLabel
  83. // ...
  84. // ... <== lastOpHelperInstr
  85. // $label: <== labelInstr
  86. IR::BranchInstr * prevBranchInstr = prevInstr->AsBranchInstr();
  87. if (prevBranchInstr->GetTarget() == labelInstr)
  88. {
  89. lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
  90. if (prevBranchInstr->IsUnconditional())
  91. {
  92. // Remove the branch to next after the helper block is moved.
  93. prevBranchInstr->Remove();
  94. }
  95. else
  96. {
  97. // Reverse the condition
  98. LowererMD::InvertBranch(prevBranchInstr);
  99. prevBranchInstr->SetTarget(lastOpHelperLabel);
  100. }
  101. }
  102. else if (prevBranchInstr->IsUnconditional())
  103. {
  104. IR::Instr * prevPrevInstr = prevInstr->GetPrevRealInstrOrLabel();
  105. if (prevPrevInstr->IsBranchInstr()
  106. && prevPrevInstr->AsBranchInstr()->IsConditional()
  107. && prevPrevInstr->AsBranchInstr()->GetTarget() == labelInstr)
  108. {
  109. // jcc $label <== prevPrevInstr
  110. // jmp $blah <== prevInstr
  111. // $helper: <== lastOpHelperLabel
  112. // ...
  113. // ... <== lastOpHelperInstr
  114. // $label: <== labelInstr
  115. // Transform to
  116. // jncc $blah <== prevPrevInstr
  117. // $label: <== labelInstr
  118. // $helper: <== lastOpHelperLabel
  119. // ...
  120. // ... <== lastOpHelperInstr
  121. // jmp $label: <== labelInstr
  122. lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
  123. LowererMD::InvertBranch(prevPrevInstr->AsBranchInstr());
  124. prevPrevInstr->AsBranchInstr()->SetTarget(prevBranchInstr->GetTarget());
  125. prevBranchInstr->Remove();
  126. }
  127. else
  128. {
  129. IR::Instr *lastOpHelperInstr = labelInstr->GetPrevRealInstr();
  130. if (lastOpHelperInstr->IsBranchInstr())
  131. {
  132. IR::BranchInstr *lastOpHelperBranchInstr = lastOpHelperInstr->AsBranchInstr();
  133. // jmp $target <== prevInstr //this is unconditional jump
  134. // $helper: <== lastOpHelperLabel
  135. // ...
  136. // jmp $labeln <== lastOpHelperInstr //Conditional/Unconditional jump
  137. // $label: <== labelInstr
  138. lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
  139. //Compensation code if its not unconditional jump
  140. if (!lastOpHelperBranchInstr->IsUnconditional())
  141. {
  142. IR::BranchInstr *branchInstr = IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelInstr, this->func);
  143. lastOpHelperBranchInstr->InsertAfter(branchInstr);
  144. }
  145. }
  146. }
  147. }
  148. }
  149. lastOpHelperLabel = NULL;
  150. }
  151. }
  152. }
  153. NEXT_INSTR_EDITING_IN_RANGE;
  154. func->m_tailInstr = lastInstr;
  155. }