ArmEmitterContext.cs 5.3 KB

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