| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- using ARMeilleure.Decoders;
- using ARMeilleure.IntermediateRepresentation;
- using ARMeilleure.Translation;
- using System;
- using System.Diagnostics;
- using static ARMeilleure.Instructions.InstEmitHelper;
- using static ARMeilleure.IntermediateRepresentation.OperandHelper;
- namespace ARMeilleure.Instructions
- {
- static partial class InstEmit
- {
- [Flags]
- private enum AccessType
- {
- None = 0,
- Ordered = 1,
- Exclusive = 2,
- OrderedEx = Ordered | Exclusive
- }
- public static void Clrex(ArmEmitterContext context)
- {
- context.Call(new _Void(NativeInterface.ClearExclusive));
- }
- public static void Dmb(ArmEmitterContext context) => EmitBarrier(context);
- public static void Dsb(ArmEmitterContext context) => EmitBarrier(context);
- public static void Ldar(ArmEmitterContext context) => EmitLdr(context, AccessType.Ordered);
- public static void Ldaxr(ArmEmitterContext context) => EmitLdr(context, AccessType.OrderedEx);
- public static void Ldxr(ArmEmitterContext context) => EmitLdr(context, AccessType.Exclusive);
- public static void Ldxp(ArmEmitterContext context) => EmitLdp(context, AccessType.Exclusive);
- public static void Ldaxp(ArmEmitterContext context) => EmitLdp(context, AccessType.OrderedEx);
- private static void EmitLdr(ArmEmitterContext context, AccessType accType)
- {
- EmitLoadEx(context, accType, pair: false);
- }
- private static void EmitLdp(ArmEmitterContext context, AccessType accType)
- {
- EmitLoadEx(context, accType, pair: true);
- }
- private static void EmitLoadEx(ArmEmitterContext context, AccessType accType, bool pair)
- {
- OpCodeMemEx op = (OpCodeMemEx)context.CurrOp;
- bool ordered = (accType & AccessType.Ordered) != 0;
- bool exclusive = (accType & AccessType.Exclusive) != 0;
- if (ordered)
- {
- EmitBarrier(context);
- }
- Operand address = context.Copy(GetIntOrSP(context, op.Rn));
- if (pair)
- {
- // Exclusive loads should be atomic. For pairwise loads, we need to
- // read all the data at once. For a 32-bits pairwise load, we do a
- // simple 64-bits load, for a 128-bits load, we need to call a special
- // method to read 128-bits atomically.
- if (op.Size == 2)
- {
- Operand value = EmitLoad(context, address, exclusive, 3);
- Operand valueLow = context.ConvertI64ToI32(value);
- valueLow = context.ZeroExtend32(OperandType.I64, valueLow);
- Operand valueHigh = context.ShiftRightUI(value, Const(32));
- SetIntOrZR(context, op.Rt, valueLow);
- SetIntOrZR(context, op.Rt2, valueHigh);
- }
- else if (op.Size == 3)
- {
- Operand value = EmitLoad(context, address, exclusive, 4);
- Operand valueLow = context.VectorExtract(OperandType.I64, value, 0);
- Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1);
- SetIntOrZR(context, op.Rt, valueLow);
- SetIntOrZR(context, op.Rt2, valueHigh);
- }
- else
- {
- throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes.");
- }
- }
- else
- {
- // 8, 16, 32 or 64-bits (non-pairwise) load.
- Operand value = EmitLoad(context, address, exclusive, op.Size);
- SetIntOrZR(context, op.Rt, value);
- }
- }
- private static Operand EmitLoad(
- ArmEmitterContext context,
- Operand address,
- bool exclusive,
- int size)
- {
- Delegate fallbackMethodDlg = null;
- if (exclusive)
- {
- switch (size)
- {
- case 0: fallbackMethodDlg = new _U8_U64 (NativeInterface.ReadByteExclusive); break;
- case 1: fallbackMethodDlg = new _U16_U64 (NativeInterface.ReadUInt16Exclusive); break;
- case 2: fallbackMethodDlg = new _U32_U64 (NativeInterface.ReadUInt32Exclusive); break;
- case 3: fallbackMethodDlg = new _U64_U64 (NativeInterface.ReadUInt64Exclusive); break;
- case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128Exclusive); break;
- }
- }
- else
- {
- switch (size)
- {
- case 0: fallbackMethodDlg = new _U8_U64 (NativeInterface.ReadByte); break;
- case 1: fallbackMethodDlg = new _U16_U64 (NativeInterface.ReadUInt16); break;
- case 2: fallbackMethodDlg = new _U32_U64 (NativeInterface.ReadUInt32); break;
- case 3: fallbackMethodDlg = new _U64_U64 (NativeInterface.ReadUInt64); break;
- case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
- }
- }
- return context.Call(fallbackMethodDlg, address);
- }
- public static void Pfrm(ArmEmitterContext context)
- {
- // Memory Prefetch, execute as no-op.
- }
- public static void Stlr(ArmEmitterContext context) => EmitStr(context, AccessType.Ordered);
- public static void Stlxr(ArmEmitterContext context) => EmitStr(context, AccessType.OrderedEx);
- public static void Stxr(ArmEmitterContext context) => EmitStr(context, AccessType.Exclusive);
- public static void Stxp(ArmEmitterContext context) => EmitStp(context, AccessType.Exclusive);
- public static void Stlxp(ArmEmitterContext context) => EmitStp(context, AccessType.OrderedEx);
- private static void EmitStr(ArmEmitterContext context, AccessType accType)
- {
- EmitStoreEx(context, accType, pair: false);
- }
- private static void EmitStp(ArmEmitterContext context, AccessType accType)
- {
- EmitStoreEx(context, accType, pair: true);
- }
- private static void EmitStoreEx(ArmEmitterContext context, AccessType accType, bool pair)
- {
- OpCodeMemEx op = (OpCodeMemEx)context.CurrOp;
- bool ordered = (accType & AccessType.Ordered) != 0;
- bool exclusive = (accType & AccessType.Exclusive) != 0;
- if (ordered)
- {
- EmitBarrier(context);
- }
- Operand address = context.Copy(GetIntOrSP(context, op.Rn));
- Operand t = GetIntOrZR(context, op.Rt);
- Operand s = null;
- if (pair)
- {
- Debug.Assert(op.Size == 2 || op.Size == 3, "Invalid size for pairwise store.");
- Operand t2 = GetIntOrZR(context, op.Rt2);
- Operand value;
- if (op.Size == 2)
- {
- value = context.BitwiseOr(t, context.ShiftLeft(t2, Const(32)));
- }
- else /* if (op.Size == 3) */
- {
- value = context.VectorInsert(context.VectorZero(), t, 0);
- value = context.VectorInsert(value, t2, 1);
- }
- s = EmitStore(context, address, value, exclusive, op.Size + 1);
- }
- else
- {
- s = EmitStore(context, address, t, exclusive, op.Size);
- }
- if (s != null)
- {
- // This is only needed for exclusive stores. The function returns 0
- // when the store is successful, and 1 otherwise.
- SetIntOrZR(context, op.Rs, s);
- }
- }
- private static Operand EmitStore(
- ArmEmitterContext context,
- Operand address,
- Operand value,
- bool exclusive,
- int size)
- {
- if (size < 3)
- {
- value = context.ConvertI64ToI32(value);
- }
- Delegate fallbackMethodDlg = null;
- if (exclusive)
- {
- switch (size)
- {
- case 0: fallbackMethodDlg = new _S32_U64_U8 (NativeInterface.WriteByteExclusive); break;
- case 1: fallbackMethodDlg = new _S32_U64_U16 (NativeInterface.WriteUInt16Exclusive); break;
- case 2: fallbackMethodDlg = new _S32_U64_U32 (NativeInterface.WriteUInt32Exclusive); break;
- case 3: fallbackMethodDlg = new _S32_U64_U64 (NativeInterface.WriteUInt64Exclusive); break;
- case 4: fallbackMethodDlg = new _S32_U64_V128(NativeInterface.WriteVector128Exclusive); break;
- }
- return context.Call(fallbackMethodDlg, address, value);
- }
- else
- {
- switch (size)
- {
- case 0: fallbackMethodDlg = new _Void_U64_U8 (NativeInterface.WriteByte); break;
- case 1: fallbackMethodDlg = new _Void_U64_U16 (NativeInterface.WriteUInt16); break;
- case 2: fallbackMethodDlg = new _Void_U64_U32 (NativeInterface.WriteUInt32); break;
- case 3: fallbackMethodDlg = new _Void_U64_U64 (NativeInterface.WriteUInt64); break;
- case 4: fallbackMethodDlg = new _Void_U64_V128(NativeInterface.WriteVector128); break;
- }
- context.Call(fallbackMethodDlg, address, value);
- return null;
- }
- }
- private static void EmitBarrier(ArmEmitterContext context)
- {
- // Note: This barrier is most likely not necessary, and probably
- // doesn't make any difference since we need to do a ton of stuff
- // (software MMU emulation) to read or write anything anyway.
- }
- }
- }
|