ArmEmitterContext.cs 5.6 KB

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