EncoderMD.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. class Encoder;
  6. enum RelocType {
  7. RelocTypeBranch, // cond, uncond branch
  8. RelocTypeCallPcrel, // calls
  9. RelocTypeLabelUse, // direct use of a label
  10. RelocTypeLabel, // points to label instr
  11. RelocTypeAlignedLabel, // points to loop-top label instr that needs alignment
  12. RelocTypeInlineeEntryOffset, // points to offset immediate in buffer
  13. };
  14. ///---------------------------------------------------------------------------
  15. ///
  16. /// class EncoderReloc
  17. ///
  18. ///---------------------------------------------------------------------------
  19. class EncodeRelocAndLabels
  20. {
  21. public:
  22. RelocType m_type;
  23. void * m_ptr; // points to encoded buffer byte or LabelInstr if RelocTypeLabel
  24. void * m_origPtr; // copy of m_ptr to be used to get offset in the source buffer during BR shortening
  25. private:
  26. union
  27. {
  28. IR::LabelInstr* m_labelInstr; // ptr to Br Label
  29. BYTE m_nopCount;
  30. uint64 m_origInlineeOffset;
  31. };
  32. bool m_isShortBr;
  33. public:
  34. void init(RelocType type, void* ptr, IR::LabelInstr* labelInstr = nullptr)
  35. {
  36. m_type = type;
  37. m_ptr = ptr;
  38. if (type == RelocTypeLabel)
  39. {
  40. // preserve original PC for labels
  41. m_origPtr = (void*)((IR::LabelInstr*)ptr)->GetPC();
  42. m_nopCount = 0;
  43. }
  44. else
  45. {
  46. m_origPtr = ptr;
  47. // in case we have to revert, we need to store original offset in code buffer
  48. if (type == RelocTypeInlineeEntryOffset)
  49. {
  50. m_origInlineeOffset = *((uint64*)m_origPtr);
  51. }
  52. else if (type == RelocTypeBranch)
  53. {
  54. Assert(labelInstr);
  55. m_labelInstr = labelInstr;
  56. m_isShortBr = false;
  57. }
  58. }
  59. }
  60. void revert()
  61. {
  62. // recover old label PC
  63. if (isLabel())
  64. {
  65. // recover old label PC and reset alignment nops
  66. // we keep aligned labels type so we align them on the second attempt.
  67. setLabelCurrPC(getLabelOrigPC());
  68. m_nopCount = 0;
  69. return;
  70. }
  71. // re-write original inlinee offset to code buffer
  72. if (m_type == RelocTypeInlineeEntryOffset)
  73. {
  74. *(uint64*) m_origPtr = m_origInlineeOffset;
  75. }
  76. if (m_type == RelocTypeBranch)
  77. {
  78. m_isShortBr = false;
  79. }
  80. m_ptr = m_origPtr;
  81. }
  82. bool isLabel() const { return isAlignedLabel() || m_type == RelocTypeLabel; }
  83. bool isAlignedLabel() const { return m_type == RelocTypeAlignedLabel; }
  84. bool isLongBr() const { return m_type == RelocTypeBranch && !m_isShortBr; }
  85. bool isShortBr() const { return m_type == RelocTypeBranch && m_isShortBr; }
  86. BYTE* getBrOpCodeByte() const { return (BYTE*)m_origPtr - 1;}
  87. IR::LabelInstr * getBrTargetLabel() const
  88. {
  89. Assert(m_type == RelocTypeBranch && m_labelInstr);
  90. return m_labelInstr;
  91. }
  92. IR::LabelInstr * getLabel() const
  93. {
  94. Assert(isLabel());
  95. return (IR::LabelInstr*) m_ptr;
  96. }
  97. // get label original PC without shortening/alignment
  98. BYTE * getLabelOrigPC() const
  99. {
  100. Assert(isLabel());
  101. return ((BYTE*) m_origPtr);
  102. }
  103. // get label PC after shortening/alignment
  104. BYTE * getLabelCurrPC() const
  105. {
  106. Assert(isLabel());
  107. return getLabel()->GetPC();
  108. }
  109. BYTE getLabelNopCount() const
  110. {
  111. Assert(isAlignedLabel());
  112. return m_nopCount;
  113. }
  114. void setLabelCurrPC(BYTE* pc)
  115. {
  116. Assert(isLabel());
  117. getLabel()->SetPC(pc);
  118. }
  119. void setLabelNopCount(BYTE nopCount)
  120. {
  121. Assert(isAlignedLabel());
  122. Assert (nopCount >= 0 && nopCount < 16);
  123. m_nopCount = nopCount;
  124. }
  125. void setAsShortBr()
  126. {
  127. Assert(m_type == RelocTypeBranch);
  128. m_isShortBr = true;
  129. }
  130. // Validates if the branch is short and its target PC fits in one byte
  131. bool validateShortBrTarget() const
  132. {
  133. return isShortBr() &&
  134. getBrTargetLabel()->GetPC() - ((BYTE*)m_ptr + 1) >= -128 &&
  135. getBrTargetLabel()->GetPC() - ((BYTE*)m_ptr + 1) <= 127;
  136. }
  137. };
  138. ///---------------------------------------------------------------------------
  139. ///
  140. /// class EncoderMD
  141. ///
  142. ///---------------------------------------------------------------------------
  143. enum Forms : BYTE;
  144. typedef JsUtil::List<EncodeRelocAndLabels, ArenaAllocator> RelocList;
  145. typedef JsUtil::List<InlineeFrameRecord*, ArenaAllocator> InlineeFrameRecords;
  146. class EncoderMD
  147. {
  148. public:
  149. EncoderMD(Func * func) : m_func(func) {}
  150. ptrdiff_t Encode(IR::Instr * instr, BYTE *pc, BYTE* beginCodeAddress = nullptr);
  151. void Init(Encoder *encoder);
  152. void ApplyRelocs(size_t codeBufferAddress);
  153. void EncodeInlineeCallInfo(IR::Instr *instr, uint32 offset);
  154. static bool TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  155. static bool TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  156. static bool SetsConditionCode(IR::Instr *instr);
  157. static bool UsesConditionCode(IR::Instr *instr);
  158. static bool IsOPEQ(IR::Instr *instr);
  159. RelocList* GetRelocList() const { return m_relocList; }
  160. int AppendRelocEntry(RelocType type, void *ptr, IR::LabelInstr *label= nullptr);
  161. int FixRelocListEntry(uint32 index, int totalBytesSaved, BYTE *buffStart, BYTE* buffEnd);
  162. void FixMaps(uint32 brOffset, uint32 bytesSaved, uint32 *inlineeFrameRecordsIndex, uint32 *inlineeFrameMapIndex, uint32 *pragmaInstToRecordOffsetIndex, uint32 *offsetBuffIndex);
  163. void UpdateRelocListWithNewBuffer(RelocList * relocList, BYTE * newBuffer, BYTE * oldBufferStart, BYTE * oldBufferEnd);
  164. #ifdef DBG
  165. void VerifyRelocList(BYTE *buffStart, BYTE *buffEnd);
  166. #endif
  167. void AddLabelReloc(BYTE* relocAddress);
  168. private:
  169. const BYTE GetOpcodeByte2(IR::Instr *instr);
  170. static Forms GetInstrForm(IR::Instr *instr);
  171. const BYTE * GetFormTemplate(IR::Instr *instr);
  172. const BYTE * GetOpbyte(IR::Instr *instr);
  173. const BYTE GetRegEncode(IR::RegOpnd *regOpnd);
  174. const BYTE GetRegEncode(RegNum reg);
  175. static const uint32 GetOpdope(IR::Instr *instr);
  176. const uint32 GetLeadIn(IR::Instr * instr);
  177. BYTE EmitModRM(IR::Instr * instr, IR::Opnd *opnd, BYTE reg1);
  178. void EmitConst(size_t val, int size, bool allowImm64 = false);
  179. BYTE EmitImmed(IR::Opnd * opnd, int opSize, int sbit, bool allowImm64 = false);
  180. static bool FitsInByte(size_t value);
  181. bool IsExtendedRegister(RegNum reg);
  182. BYTE GetMod(IR::IndirOpnd * opr, int* pDispSize);
  183. BYTE GetMod(IR::SymOpnd * opr, int* pDispSize, RegNum& rmReg);
  184. BYTE GetMod(size_t offset, bool regIsRbpOrR13, int * pDispSize);
  185. BYTE GetRexByte(BYTE rexCode, IR::Opnd * opnd);
  186. BYTE GetRexByte(BYTE rexCode, RegNum reg);
  187. int GetOpndSize(IR::Opnd * opnd);
  188. void EmitRexByte(BYTE * prexByte, BYTE rexByte, bool skipRexByte, bool reservedRexByte);
  189. enum
  190. {
  191. REXOVERRIDE = 0x40,
  192. REXW = 8,
  193. REXR = 4,
  194. REXX = 2,
  195. REXB = 1,
  196. };
  197. static const BYTE Mod00 = 0x00 << 6;
  198. static const BYTE Mod01 = 0x01 << 6;
  199. static const BYTE Mod10 = 0x02 << 6;
  200. static const BYTE Mod11 = 0x03 << 6;
  201. private:
  202. Func * m_func;
  203. Encoder * m_encoder;
  204. BYTE * m_pc;
  205. RelocList * m_relocList;
  206. int m_lastLoopLabelPosition;
  207. };