ArmEmitterContext.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using ARMeilleure.CodeGen.Linking;
  2. using ARMeilleure.Common;
  3. using ARMeilleure.Decoders;
  4. using ARMeilleure.Diagnostics;
  5. using ARMeilleure.Instructions;
  6. using ARMeilleure.IntermediateRepresentation;
  7. using ARMeilleure.Memory;
  8. using ARMeilleure.State;
  9. using ARMeilleure.Translation.PTC;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Reflection;
  13. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  14. namespace ARMeilleure.Translation
  15. {
  16. class ArmEmitterContext : EmitterContext
  17. {
  18. private readonly Dictionary<ulong, Operand> _labels;
  19. private OpCode _optOpLastCompare;
  20. private OpCode _optOpLastFlagSet;
  21. private Operand _optCmpTempN;
  22. private Operand _optCmpTempM;
  23. private Block _currBlock;
  24. public Block CurrBlock
  25. {
  26. get
  27. {
  28. return _currBlock;
  29. }
  30. set
  31. {
  32. _currBlock = value;
  33. ResetBlockState();
  34. }
  35. }
  36. public OpCode CurrOp { get; set; }
  37. public IMemoryManager Memory { get; }
  38. public bool HasPtc { get; }
  39. public EntryTable<uint> CountTable { get; }
  40. public AddressTable<ulong> FunctionTable { get; }
  41. public TranslatorStubs Stubs { get; }
  42. public ulong EntryAddress { get; }
  43. public bool HighCq { get; }
  44. public Aarch32Mode Mode { get; }
  45. private int _ifThenBlockStateIndex = 0;
  46. private Condition[] _ifThenBlockState = { };
  47. public bool IsInIfThenBlock => _ifThenBlockStateIndex < _ifThenBlockState.Length;
  48. public Condition CurrentIfThenBlockCond => _ifThenBlockState[_ifThenBlockStateIndex];
  49. public ArmEmitterContext(
  50. IMemoryManager memory,
  51. EntryTable<uint> countTable,
  52. AddressTable<ulong> funcTable,
  53. TranslatorStubs stubs,
  54. ulong entryAddress,
  55. bool highCq,
  56. Aarch32Mode mode)
  57. {
  58. HasPtc = Ptc.State != PtcState.Disabled;
  59. Memory = memory;
  60. CountTable = countTable;
  61. FunctionTable = funcTable;
  62. Stubs = stubs;
  63. EntryAddress = entryAddress;
  64. HighCq = highCq;
  65. Mode = mode;
  66. _labels = new Dictionary<ulong, Operand>();
  67. }
  68. public override Operand Call(MethodInfo info, params Operand[] callArgs)
  69. {
  70. if (!HasPtc)
  71. {
  72. return base.Call(info, callArgs);
  73. }
  74. else
  75. {
  76. int index = Delegates.GetDelegateIndex(info);
  77. IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
  78. OperandType returnType = GetOperandType(info.ReturnType);
  79. Symbol symbol = new Symbol(SymbolType.DelegateTable, (ulong)index);
  80. Symbols.Add((ulong)funcPtr.ToInt64(), info.Name);
  81. return Call(Const(funcPtr.ToInt64(), symbol), returnType, callArgs);
  82. }
  83. }
  84. public Operand GetLabel(ulong address)
  85. {
  86. if (!_labels.TryGetValue(address, out Operand label))
  87. {
  88. label = Label();
  89. _labels.Add(address, label);
  90. }
  91. return label;
  92. }
  93. public void MarkComparison(Operand n, Operand m)
  94. {
  95. _optOpLastCompare = CurrOp;
  96. _optCmpTempN = Copy(n);
  97. _optCmpTempM = Copy(m);
  98. }
  99. public void MarkFlagSet(PState stateFlag)
  100. {
  101. // Set this only if any of the NZCV flag bits were modified.
  102. // This is used to ensure that when emiting a direct IL branch
  103. // instruction for compare + branch sequences, we're not expecting
  104. // to use comparison values from an old instruction, when in fact
  105. // the flags were already overwritten by another instruction further along.
  106. if (stateFlag >= PState.VFlag)
  107. {
  108. _optOpLastFlagSet = CurrOp;
  109. }
  110. }
  111. private void ResetBlockState()
  112. {
  113. _optOpLastCompare = null;
  114. _optOpLastFlagSet = null;
  115. }
  116. public Operand TryGetComparisonResult(Condition condition)
  117. {
  118. if (_optOpLastCompare == null || _optOpLastCompare != _optOpLastFlagSet)
  119. {
  120. return default;
  121. }
  122. Operand n = _optCmpTempN;
  123. Operand m = _optCmpTempM;
  124. InstName cmpName = _optOpLastCompare.Instruction.Name;
  125. if (cmpName == InstName.Subs)
  126. {
  127. switch (condition)
  128. {
  129. case Condition.Eq: return ICompareEqual (n, m);
  130. case Condition.Ne: return ICompareNotEqual (n, m);
  131. case Condition.GeUn: return ICompareGreaterOrEqualUI(n, m);
  132. case Condition.LtUn: return ICompareLessUI (n, m);
  133. case Condition.GtUn: return ICompareGreaterUI (n, m);
  134. case Condition.LeUn: return ICompareLessOrEqualUI (n, m);
  135. case Condition.Ge: return ICompareGreaterOrEqual (n, m);
  136. case Condition.Lt: return ICompareLess (n, m);
  137. case Condition.Gt: return ICompareGreater (n, m);
  138. case Condition.Le: return ICompareLessOrEqual (n, m);
  139. }
  140. }
  141. else if (cmpName == InstName.Adds && _optOpLastCompare is IOpCodeAluImm op)
  142. {
  143. // There are several limitations that needs to be taken into account for CMN comparisons:
  144. // - The unsigned comparisons are not valid, as they depend on the
  145. // carry flag value, and they will have different values for addition and
  146. // subtraction. For addition, it's carry, and for subtraction, it's borrow.
  147. // So, we need to make sure we're not doing a unsigned compare for the CMN case.
  148. // - We can only do the optimization for the immediate variants,
  149. // because when the second operand value is exactly INT_MIN, we can't
  150. // negate the value as theres no positive counterpart.
  151. // Such invalid values can't be encoded on the immediate encodings.
  152. if (op.RegisterSize == RegisterSize.Int32)
  153. {
  154. m = Const((int)-op.Immediate);
  155. }
  156. else
  157. {
  158. m = Const(-op.Immediate);
  159. }
  160. switch (condition)
  161. {
  162. case Condition.Eq: return ICompareEqual (n, m);
  163. case Condition.Ne: return ICompareNotEqual (n, m);
  164. case Condition.Ge: return ICompareGreaterOrEqual(n, m);
  165. case Condition.Lt: return ICompareLess (n, m);
  166. case Condition.Gt: return ICompareGreater (n, m);
  167. case Condition.Le: return ICompareLessOrEqual (n, m);
  168. }
  169. }
  170. return default;
  171. }
  172. public void SetIfThenBlockState(Condition[] state)
  173. {
  174. _ifThenBlockState = state;
  175. _ifThenBlockStateIndex = 0;
  176. }
  177. public void AdvanceIfThenBlockState()
  178. {
  179. if (IsInIfThenBlock)
  180. {
  181. _ifThenBlockStateIndex++;
  182. }
  183. }
  184. }
  185. }