aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Instructions/InstEmitHelper.cs')
-rw-r--r--ARMeilleure/Instructions/InstEmitHelper.cs32
1 files changed, 22 insertions, 10 deletions
diff --git a/ARMeilleure/Instructions/InstEmitHelper.cs b/ARMeilleure/Instructions/InstEmitHelper.cs
index f5495c66..a4227543 100644
--- a/ARMeilleure/Instructions/InstEmitHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitHelper.cs
@@ -144,22 +144,34 @@ namespace ARMeilleure.Instructions
}
}
- public static void EmitBxWritePc(ArmEmitterContext context, Operand pc)
+ public static bool IsA32Return(ArmEmitterContext context)
{
+ switch (context.CurrOp)
+ {
+ case IOpCode32MemMult op:
+ return true; // Setting PC using LDM is nearly always a return.
+ case OpCode32AluRsImm op:
+ return op.Rm == RegisterAlias.Aarch32Lr;
+ case OpCode32AluRsReg op:
+ return op.Rm == RegisterAlias.Aarch32Lr;
+ case OpCode32AluReg op:
+ return op.Rm == RegisterAlias.Aarch32Lr;
+ case OpCode32Mem op:
+ return op.Rn == RegisterAlias.Aarch32Sp && op.WBack && !op.Index; // Setting PC to an address stored on the stack is nearly always a return.
+ }
+ return false;
+ }
+
+ public static void EmitBxWritePc(ArmEmitterContext context, Operand pc, int sourceRegister = 0)
+ {
+ bool isReturn = sourceRegister == RegisterAlias.Aarch32Lr || IsA32Return(context);
Operand mode = context.BitwiseAnd(pc, Const(1));
SetFlag(context, PState.TFlag, mode);
- Operand lblArmMode = Label();
-
- context.BranchIfTrue(lblArmMode, mode);
-
- // Make this count as a call, the translator will ignore the low bit for the address.
- context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(pc, Const((int)InstEmitFlowHelper.CallFlag))));
-
- context.MarkLabel(lblArmMode);
+ Operand addr = context.ConditionalSelect(mode, context.BitwiseOr(pc, Const((int)InstEmitFlowHelper.CallFlag)), context.BitwiseAnd(pc, Const(~3)));
- context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseOr(context.BitwiseAnd(pc, Const(~3)), Const((int)InstEmitFlowHelper.CallFlag))));
+ InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn);
}
public static Operand GetIntOrZR(ArmEmitterContext context, int regIndex)