InstEmitFlowHelper.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.State;
  4. using ARMeilleure.Translation;
  5. using static ARMeilleure.Instructions.InstEmitHelper;
  6. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  7. namespace ARMeilleure.Instructions
  8. {
  9. static class InstEmitFlowHelper
  10. {
  11. public const ulong CallFlag = 1;
  12. public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
  13. {
  14. if (cond != Condition.Al)
  15. {
  16. context.BranchIfTrue(target, GetCondTrue(context, cond));
  17. }
  18. else
  19. {
  20. context.Branch(target);
  21. }
  22. }
  23. public static Operand GetCondTrue(ArmEmitterContext context, Condition condition)
  24. {
  25. Operand cmpResult = context.TryGetComparisonResult(condition);
  26. if (cmpResult != null)
  27. {
  28. return cmpResult;
  29. }
  30. Operand value = Const(1);
  31. Operand Inverse(Operand val)
  32. {
  33. return context.BitwiseExclusiveOr(val, Const(1));
  34. }
  35. switch (condition)
  36. {
  37. case Condition.Eq:
  38. value = GetFlag(PState.ZFlag);
  39. break;
  40. case Condition.Ne:
  41. value = Inverse(GetFlag(PState.ZFlag));
  42. break;
  43. case Condition.GeUn:
  44. value = GetFlag(PState.CFlag);
  45. break;
  46. case Condition.LtUn:
  47. value = Inverse(GetFlag(PState.CFlag));
  48. break;
  49. case Condition.Mi:
  50. value = GetFlag(PState.NFlag);
  51. break;
  52. case Condition.Pl:
  53. value = Inverse(GetFlag(PState.NFlag));
  54. break;
  55. case Condition.Vs:
  56. value = GetFlag(PState.VFlag);
  57. break;
  58. case Condition.Vc:
  59. value = Inverse(GetFlag(PState.VFlag));
  60. break;
  61. case Condition.GtUn:
  62. {
  63. Operand c = GetFlag(PState.CFlag);
  64. Operand z = GetFlag(PState.ZFlag);
  65. value = context.BitwiseAnd(c, Inverse(z));
  66. break;
  67. }
  68. case Condition.LeUn:
  69. {
  70. Operand c = GetFlag(PState.CFlag);
  71. Operand z = GetFlag(PState.ZFlag);
  72. value = context.BitwiseOr(Inverse(c), z);
  73. break;
  74. }
  75. case Condition.Ge:
  76. {
  77. Operand n = GetFlag(PState.NFlag);
  78. Operand v = GetFlag(PState.VFlag);
  79. value = context.ICompareEqual(n, v);
  80. break;
  81. }
  82. case Condition.Lt:
  83. {
  84. Operand n = GetFlag(PState.NFlag);
  85. Operand v = GetFlag(PState.VFlag);
  86. value = context.ICompareNotEqual(n, v);
  87. break;
  88. }
  89. case Condition.Gt:
  90. {
  91. Operand n = GetFlag(PState.NFlag);
  92. Operand z = GetFlag(PState.ZFlag);
  93. Operand v = GetFlag(PState.VFlag);
  94. value = context.BitwiseAnd(Inverse(z), context.ICompareEqual(n, v));
  95. break;
  96. }
  97. case Condition.Le:
  98. {
  99. Operand n = GetFlag(PState.NFlag);
  100. Operand z = GetFlag(PState.ZFlag);
  101. Operand v = GetFlag(PState.VFlag);
  102. value = context.BitwiseOr(z, context.ICompareNotEqual(n, v));
  103. break;
  104. }
  105. }
  106. return value;
  107. }
  108. public static void EmitCall(ArmEmitterContext context, ulong immediate)
  109. {
  110. context.Return(Const(immediate | CallFlag));
  111. }
  112. public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
  113. {
  114. EmitVirtualCallOrJump(context, target, isJump: false);
  115. }
  116. public static void EmitVirtualJump(ArmEmitterContext context, Operand target)
  117. {
  118. EmitVirtualCallOrJump(context, target, isJump: true);
  119. }
  120. private static void EmitVirtualCallOrJump(ArmEmitterContext context, Operand target, bool isJump)
  121. {
  122. context.Return(context.BitwiseOr(target, Const(target.Type, (long)CallFlag)));
  123. }
  124. private static void EmitContinueOrReturnCheck(ArmEmitterContext context, Operand retVal)
  125. {
  126. // Note: The return value of the called method will be placed
  127. // at the Stack, the return value is always a Int64 with the
  128. // return address of the function. We check if the address is
  129. // correct, if it isn't we keep returning until we reach the dispatcher.
  130. ulong nextAddr = GetNextOpAddress(context.CurrOp);
  131. if (context.CurrBlock.Next != null)
  132. {
  133. Operand lblContinue = Label();
  134. context.BranchIfTrue(lblContinue, context.ICompareEqual(retVal, Const(nextAddr)));
  135. context.Return(Const(nextAddr));
  136. context.MarkLabel(lblContinue);
  137. }
  138. else
  139. {
  140. context.Return(Const(nextAddr));
  141. }
  142. }
  143. private static ulong GetNextOpAddress(OpCode op)
  144. {
  145. return op.Address + (ulong)op.OpCodeSizeInBytes;
  146. }
  147. }
  148. }