ArmEmitterContext.cs 6.8 KB

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