diff options
Diffstat (limited to 'ARMeilleure/Translation/ArmEmitterContext.cs')
-rw-r--r-- | ARMeilleure/Translation/ArmEmitterContext.cs | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/ARMeilleure/Translation/ArmEmitterContext.cs b/ARMeilleure/Translation/ArmEmitterContext.cs index 48254de4..238f8508 100644 --- a/ARMeilleure/Translation/ArmEmitterContext.cs +++ b/ARMeilleure/Translation/ArmEmitterContext.cs @@ -39,6 +39,8 @@ namespace ARMeilleure.Translation } } + private bool _pendingQcFlagSync; + public OpCode CurrOp { get; set; } public IMemoryManager Memory { get; } @@ -81,6 +83,8 @@ namespace ARMeilleure.Translation public override Operand Call(MethodInfo info, params Operand[] callArgs) { + SyncQcFlag(); + if (!HasPtc) { return base.Call(info, callArgs); @@ -139,6 +143,51 @@ namespace ARMeilleure.Translation _optOpLastFlagSet = null; } + public void SetPendingQcFlagSync() + { + _pendingQcFlagSync = true; + } + + public void SyncQcFlag() + { + if (_pendingQcFlagSync) + { + if (Optimizations.UseAdvSimd) + { + Operand fpsr = AddIntrinsicInt(Intrinsic.Arm64MrsFpsr); + + uint qcFlagMask = (uint)FPSR.Qc; + + Operand qcClearLabel = Label(); + + BranchIfFalse(qcClearLabel, BitwiseAnd(fpsr, Const(qcFlagMask))); + + AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0)); + InstEmitHelper.SetFpFlag(this, FPState.QcFlag, Const(1)); + + MarkLabel(qcClearLabel); + } + + _pendingQcFlagSync = false; + } + } + + public void ClearQcFlag() + { + if (Optimizations.UseAdvSimd) + { + AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0)); + } + } + + public void ClearQcFlagIfModified() + { + if (_pendingQcFlagSync && Optimizations.UseAdvSimd) + { + AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0)); + } + } + public Operand TryGetComparisonResult(Condition condition) { if (_optOpLastCompare == null || _optOpLastCompare != _optOpLastFlagSet) |