ArmEmitterContext.cs 5.8 KB

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