ArmEmitterContext.cs 5.6 KB

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