InstEmitMemoryEx.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.Translation; 4 using System; 5 using System.Diagnostics; 6 using static ARMeilleure.Instructions.InstEmitHelper; 7 using static ARMeilleure.Instructions.InstEmitMemoryExHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit 13 { 14 [Flags] 15 private enum AccessType 16 { 17 None = 0, 18 Ordered = 1, 19 Exclusive = 2, 20 OrderedEx = Ordered | Exclusive, 21 } 22 23 public static void Clrex(ArmEmitterContext context) 24 { 25 EmitClearExclusive(context); 26 } 27 28 public static void Csdb(ArmEmitterContext context) 29 { 30 // Execute as no-op. 31 } 32 33 public static void Dmb(ArmEmitterContext context) => EmitBarrier(context); 34 public static void Dsb(ArmEmitterContext context) => EmitBarrier(context); 35 36 public static void Ldar(ArmEmitterContext context) => EmitLdr(context, AccessType.Ordered); 37 public static void Ldaxr(ArmEmitterContext context) => EmitLdr(context, AccessType.OrderedEx); 38 public static void Ldxr(ArmEmitterContext context) => EmitLdr(context, AccessType.Exclusive); 39 public static void Ldxp(ArmEmitterContext context) => EmitLdp(context, AccessType.Exclusive); 40 public static void Ldaxp(ArmEmitterContext context) => EmitLdp(context, AccessType.OrderedEx); 41 42 private static void EmitLdr(ArmEmitterContext context, AccessType accType) 43 { 44 EmitLoadEx(context, accType, pair: false); 45 } 46 47 private static void EmitLdp(ArmEmitterContext context, AccessType accType) 48 { 49 EmitLoadEx(context, accType, pair: true); 50 } 51 52 private static void EmitLoadEx(ArmEmitterContext context, AccessType accType, bool pair) 53 { 54 OpCodeMemEx op = (OpCodeMemEx)context.CurrOp; 55 56 bool ordered = (accType & AccessType.Ordered) != 0; 57 bool exclusive = (accType & AccessType.Exclusive) != 0; 58 59 if (ordered) 60 { 61 EmitBarrier(context); 62 } 63 64 Operand address = context.Copy(GetIntOrSP(context, op.Rn)); 65 66 if (pair) 67 { 68 // Exclusive loads should be atomic. For pairwise loads, we need to 69 // read all the data at once. For a 32-bits pairwise load, we do a 70 // simple 64-bits load, for a 128-bits load, we need to call a special 71 // method to read 128-bits atomically. 72 if (op.Size == 2) 73 { 74 Operand value = EmitLoadExclusive(context, address, exclusive, 3); 75 76 Operand valueLow = context.ConvertI64ToI32(value); 77 78 valueLow = context.ZeroExtend32(OperandType.I64, valueLow); 79 80 Operand valueHigh = context.ShiftRightUI(value, Const(32)); 81 82 SetIntOrZR(context, op.Rt, valueLow); 83 SetIntOrZR(context, op.Rt2, valueHigh); 84 } 85 else if (op.Size == 3) 86 { 87 Operand value = EmitLoadExclusive(context, address, exclusive, 4); 88 89 Operand valueLow = context.VectorExtract(OperandType.I64, value, 0); 90 Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1); 91 92 SetIntOrZR(context, op.Rt, valueLow); 93 SetIntOrZR(context, op.Rt2, valueHigh); 94 } 95 else 96 { 97 throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes."); 98 } 99 } 100 else 101 { 102 // 8, 16, 32 or 64-bits (non-pairwise) load. 103 Operand value = EmitLoadExclusive(context, address, exclusive, op.Size); 104 105 SetIntOrZR(context, op.Rt, value); 106 } 107 } 108 109 public static void Prfm(ArmEmitterContext context) 110 { 111 // Memory Prefetch, execute as no-op. 112 } 113 114 public static void Stlr(ArmEmitterContext context) => EmitStr(context, AccessType.Ordered); 115 public static void Stlxr(ArmEmitterContext context) => EmitStr(context, AccessType.OrderedEx); 116 public static void Stxr(ArmEmitterContext context) => EmitStr(context, AccessType.Exclusive); 117 public static void Stxp(ArmEmitterContext context) => EmitStp(context, AccessType.Exclusive); 118 public static void Stlxp(ArmEmitterContext context) => EmitStp(context, AccessType.OrderedEx); 119 120 private static void EmitStr(ArmEmitterContext context, AccessType accType) 121 { 122 EmitStoreEx(context, accType, pair: false); 123 } 124 125 private static void EmitStp(ArmEmitterContext context, AccessType accType) 126 { 127 EmitStoreEx(context, accType, pair: true); 128 } 129 130 private static void EmitStoreEx(ArmEmitterContext context, AccessType accType, bool pair) 131 { 132 OpCodeMemEx op = (OpCodeMemEx)context.CurrOp; 133 134 bool ordered = (accType & AccessType.Ordered) != 0; 135 bool exclusive = (accType & AccessType.Exclusive) != 0; 136 137 Operand address = context.Copy(GetIntOrSP(context, op.Rn)); 138 139 Operand t = GetIntOrZR(context, op.Rt); 140 141 if (pair) 142 { 143 Debug.Assert(op.Size == 2 || op.Size == 3, "Invalid size for pairwise store."); 144 145 Operand t2 = GetIntOrZR(context, op.Rt2); 146 147 Operand value; 148 149 if (op.Size == 2) 150 { 151 value = context.BitwiseOr(t, context.ShiftLeft(t2, Const(32))); 152 } 153 else /* if (op.Size == 3) */ 154 { 155 value = context.VectorInsert(context.VectorZero(), t, 0); 156 value = context.VectorInsert(value, t2, 1); 157 } 158 159 EmitStoreExclusive(context, address, value, exclusive, op.Size + 1, op.Rs, a32: false); 160 } 161 else 162 { 163 EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false); 164 } 165 166 if (ordered) 167 { 168 EmitBarrier(context); 169 } 170 } 171 172 private static void EmitBarrier(ArmEmitterContext context) 173 { 174 context.MemoryBarrier(); 175 } 176 } 177 }