Refactoring

This commit is contained in:
gdkchan 2019-02-25 09:27:10 -03:00
commit 18678035f5
15 changed files with 102 additions and 103 deletions

View file

@ -41,18 +41,18 @@ namespace ChocolArm64.Translation
{
switch (ld.IoType)
{
case IoType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~_intAwOutputs; break;
case IoType.Int: IntInputs |= (1L << ld.Index) & ~_intAwOutputs; break;
case IoType.Vector: VecInputs |= (1L << ld.Index) & ~_vecAwOutputs; break;
case VarType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~_intAwOutputs; break;
case VarType.Int: IntInputs |= (1L << ld.Index) & ~_intAwOutputs; break;
case VarType.Vector: VecInputs |= (1L << ld.Index) & ~_vecAwOutputs; break;
}
}
else if (emitter is ILOpCodeStore st && ILMethodBuilder.IsRegIndex(st.Index))
{
switch (st.IoType)
{
case IoType.Flag: IntOutputs |= (1L << st.Index) << 32; break;
case IoType.Int: IntOutputs |= 1L << st.Index; break;
case IoType.Vector: VecOutputs |= 1L << st.Index; break;
case VarType.Flag: IntOutputs |= (1L << st.Index) << 32; break;
case VarType.Int: IntOutputs |= 1L << st.Index; break;
case VarType.Vector: VecOutputs |= 1L << st.Index; break;
}
}
else if (emitter is ILOpCodeStoreState)

View file

@ -336,8 +336,8 @@ namespace ChocolArm64.Translation
InstEmitAluHelper.EmitAluLoadOpers(this);
Stloc(CmpOptTmp2Index, IoType.Int);
Stloc(CmpOptTmp1Index, IoType.Int);
Stloc(CmpOptTmp2Index, VarType.Int);
Stloc(CmpOptTmp1Index, VarType.Int);
}
private Dictionary<Condition, OpCode> _branchOps = new Dictionary<Condition, OpCode>()
@ -361,8 +361,8 @@ namespace ChocolArm64.Translation
{
if (_optOpLastCompare.Emitter == InstEmit.Subs)
{
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp2Index, VarType.Int, _optOpLastCompare.RegisterSize);
Emit(_branchOps[cond], target);
@ -384,7 +384,7 @@ namespace ChocolArm64.Translation
//Such invalid values can't be encoded on the immediate encodings.
if (_optOpLastCompare is IOpCodeAluImm64 op)
{
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize);
if (_optOpLastCompare.RegisterSize == RegisterSize.Int32)
{
@ -506,14 +506,14 @@ namespace ChocolArm64.Translation
{
if (amount > 0)
{
Stloc(RorTmpIndex, IoType.Int);
Ldloc(RorTmpIndex, IoType.Int);
Stloc(RorTmpIndex, VarType.Int);
Ldloc(RorTmpIndex, VarType.Int);
EmitLdc_I4(amount);
Emit(OpCodes.Shr_Un);
Ldloc(RorTmpIndex, IoType.Int);
Ldloc(RorTmpIndex, VarType.Int);
EmitLdc_I4(CurrOp.GetBitsCount() - amount);
@ -561,7 +561,7 @@ namespace ChocolArm64.Translation
public void EmitLdarg(int index)
{
_ilBlock.Add(new ILOpCodeLoad(index, IoType.Arg));
_ilBlock.Add(new ILOpCodeLoad(index, VarType.Arg));
}
public void EmitLdintzr(int index)
@ -615,13 +615,13 @@ namespace ChocolArm64.Translation
public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index);
public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index);
public void EmitLdint(int index) => Ldloc(index, IoType.Int);
public void EmitStint(int index) => Stloc(index, IoType.Int);
public void EmitLdint(int index) => Ldloc(index, VarType.Int);
public void EmitStint(int index) => Stloc(index, VarType.Int);
public void EmitLdvec(int index) => Ldloc(index, IoType.Vector);
public void EmitStvec(int index) => Stloc(index, IoType.Vector);
public void EmitLdvec(int index) => Ldloc(index, VarType.Vector);
public void EmitStvec(int index) => Stloc(index, VarType.Vector);
public void EmitLdflg(int index) => Ldloc(index, IoType.Flag);
public void EmitLdflg(int index) => Ldloc(index, VarType.Flag);
public void EmitStflg(int index)
{
//Set this only if any of the NZCV flag bits were modified.
@ -634,20 +634,20 @@ namespace ChocolArm64.Translation
_optOpLastFlagSet = CurrOp;
}
Stloc(index, IoType.Flag);
Stloc(index, VarType.Flag);
}
private void Ldloc(int index, IoType ioType)
private void Ldloc(int index, VarType ioType)
{
_ilBlock.Add(new ILOpCodeLoad(index, ioType, CurrOp.RegisterSize));
}
private void Ldloc(int index, IoType ioType, RegisterSize registerSize)
private void Ldloc(int index, VarType ioType, RegisterSize registerSize)
{
_ilBlock.Add(new ILOpCodeLoad(index, ioType, registerSize));
}
private void Stloc(int index, IoType ioType)
private void Stloc(int index, VarType ioType)
{
_ilBlock.Add(new ILOpCodeStore(index, ioType, CurrOp.RegisterSize));
}

View file

@ -8,7 +8,10 @@ namespace ChocolArm64.Translation
{
class ILMethodBuilder
{
public LocalAlloc LocalAlloc { get; private set; }
private const int RegsCount = 32;
private const int RegsMask = RegsCount - 1;
public RegisterUsage RegUsage { get; private set; }
public ILGenerator Generator { get; private set; }
@ -38,20 +41,20 @@ namespace ChocolArm64.Translation
public TranslatedSub GetSubroutine(TranslationTier tier)
{
LocalAlloc = new LocalAlloc();
RegUsage = new RegisterUsage();
LocalAlloc.BuildUses(_ilBlocks[0]);
RegUsage.BuildUses(_ilBlocks[0]);
DynamicMethod method = new DynamicMethod(_subName, typeof(long), TranslatedSub.FixedArgTypes);
Generator = method.GetILGenerator();
TranslatedSub subroutine = new TranslatedSub(method, tier);
_locals = new Dictionary<Register, int>();
_localsCount = 0;
Generator = method.GetILGenerator();
foreach (ILBlock ilBlock in _ilBlocks)
{
ilBlock.Emit(this);
@ -90,13 +93,13 @@ namespace ChocolArm64.Translation
public static Register GetRegFromBit(int bit, RegisterType baseType)
{
if (bit < 32)
if (bit < RegsCount)
{
return new Register(bit, baseType);
}
else if (baseType == RegisterType.Int)
{
return new Register(bit & 0x1f, RegisterType.Flag);
return new Register(bit & RegsMask, RegisterType.Flag);
}
else
{
@ -106,7 +109,7 @@ namespace ChocolArm64.Translation
public static bool IsRegIndex(int index)
{
return (uint)index < 32;
return (uint)index < RegsCount;
}
}
}

View file

@ -4,16 +4,16 @@ namespace ChocolArm64.Translation
{
struct ILOpCode : IILEmit
{
private OpCode _ilOp;
public OpCode ILOp { get; }
public ILOpCode(OpCode ilOp)
{
_ilOp = ilOp;
ILOp = ilOp;
}
public void Emit(ILMethodBuilder context)
{
context.Generator.Emit(_ilOp);
context.Generator.Emit(ILOp);
}
}
}

View file

@ -4,18 +4,18 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeBranch : IILEmit
{
private OpCode _ilOp;
private ILLabel _label;
public OpCode ILOp { get; }
public ILLabel Label { get; }
public ILOpCodeBranch(OpCode ilOp, ILLabel label)
{
_ilOp = ilOp;
_label = label;
ILOp = ilOp;
Label = label;
}
public void Emit(ILMethodBuilder context)
{
context.Generator.Emit(_ilOp, _label.GetLabel(context));
context.Generator.Emit(ILOp, Label.GetLabel(context));
}
}
}

View file

@ -5,9 +5,9 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeCall : IILEmit
{
public MethodInfo Info { get; private set; }
public MethodInfo Info { get; }
public bool IsVirtual { get; private set; }
public bool IsVirtual { get; }
public ILOpCodeCall(MethodInfo info, bool isVirtual)
{

View file

@ -16,6 +16,8 @@ namespace ChocolArm64.Translation
private ImmVal _value;
public long Value => _value.I8;
private enum ConstType
{
Int32,

View file

@ -5,13 +5,13 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeLoad : IILEmit
{
public int Index { get; private set; }
public int Index { get; }
public IoType IoType { get; private set; }
public VarType IoType { get; }
public RegisterSize RegisterSize { get; private set; }
public RegisterSize RegisterSize { get; }
public ILOpCodeLoad(int index, IoType ioType, RegisterSize registerSize = 0)
public ILOpCodeLoad(int index, VarType ioType, RegisterSize registerSize = 0)
{
Index = index;
IoType = ioType;
@ -22,11 +22,11 @@ namespace ChocolArm64.Translation
{
switch (IoType)
{
case IoType.Arg: context.Generator.EmitLdarg(Index); break;
case VarType.Arg: context.Generator.EmitLdarg(Index); break;
case IoType.Flag: EmitLdloc(context, Index, RegisterType.Flag); break;
case IoType.Int: EmitLdloc(context, Index, RegisterType.Int); break;
case IoType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break;
case VarType.Flag: EmitLdloc(context, Index, RegisterType.Flag); break;
case VarType.Int: EmitLdloc(context, Index, RegisterType.Int); break;
case VarType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break;
}
}

View file

@ -5,7 +5,7 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeLoadField : IILEmit
{
public FieldInfo Info { get; private set; }
public FieldInfo Info { get; }
public ILOpCodeLoadField(FieldInfo info)
{

View file

@ -17,13 +17,13 @@ namespace ChocolArm64.Translation
public void Emit(ILMethodBuilder context)
{
long intInputs = context.LocalAlloc.GetIntInputs(_block);
long vecInputs = context.LocalAlloc.GetVecInputs(_block);
long intInputs = context.RegUsage.GetIntInputs(_block);
long vecInputs = context.RegUsage.GetVecInputs(_block);
if (Optimizations.AssumeStrictAbiCompliance && context.IsSubComplete)
{
intInputs = LocalAlloc.ClearCallerSavedIntRegs(intInputs, context.IsAarch64);
vecInputs = LocalAlloc.ClearCallerSavedVecRegs(vecInputs, context.IsAarch64);
intInputs = RegisterUsage.ClearCallerSavedIntRegs(intInputs, context.IsAarch64);
vecInputs = RegisterUsage.ClearCallerSavedVecRegs(vecInputs, context.IsAarch64);
}
LoadLocals(context, intInputs, RegisterType.Int);

View file

@ -2,16 +2,16 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeLog : IILEmit
{
private string _text;
public string Text { get; }
public ILOpCodeLog(string text)
{
_text = text;
Text = text;
}
public void Emit(ILMethodBuilder context)
{
context.Generator.EmitWriteLine(_text);
context.Generator.EmitWriteLine(Text);
}
}
}

View file

@ -5,13 +5,13 @@ namespace ChocolArm64.Translation
{
struct ILOpCodeStore : IILEmit
{
public int Index { get; private set; }
public int Index { get; }
public IoType IoType { get; private set; }
public VarType IoType { get; }
public RegisterSize RegisterSize { get; private set; }
public RegisterSize RegisterSize { get; }
public ILOpCodeStore(int index, IoType ioType, RegisterSize registerSize = 0)
public ILOpCodeStore(int index, VarType ioType, RegisterSize registerSize = 0)
{
Index = index;
IoType = ioType;
@ -22,11 +22,11 @@ namespace ChocolArm64.Translation
{
switch (IoType)
{
case IoType.Arg: context.Generator.EmitStarg(Index); break;
case VarType.Arg: context.Generator.EmitStarg(Index); break;
case IoType.Flag: EmitStloc(context, Index, RegisterType.Flag); break;
case IoType.Int: EmitStloc(context, Index, RegisterType.Int); break;
case IoType.Vector: EmitStloc(context, Index, RegisterType.Vector); break;
case VarType.Flag: EmitStloc(context, Index, RegisterType.Flag); break;
case VarType.Int: EmitStloc(context, Index, RegisterType.Int); break;
case VarType.Vector: EmitStloc(context, Index, RegisterType.Vector); break;
}
}

View file

@ -14,13 +14,13 @@ namespace ChocolArm64.Translation
public void Emit(ILMethodBuilder context)
{
long intOutputs = context.LocalAlloc.GetIntOutputs(_block);
long vecOutputs = context.LocalAlloc.GetVecOutputs(_block);
long intOutputs = context.RegUsage.GetIntOutputs(_block);
long vecOutputs = context.RegUsage.GetVecOutputs(_block);
if (Optimizations.AssumeStrictAbiCompliance && context.IsSubComplete)
{
intOutputs = LocalAlloc.ClearCallerSavedIntRegs(intOutputs, context.IsAarch64);
vecOutputs = LocalAlloc.ClearCallerSavedVecRegs(vecOutputs, context.IsAarch64);
intOutputs = RegisterUsage.ClearCallerSavedIntRegs(intOutputs, context.IsAarch64);
vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, context.IsAarch64);
}
StoreLocals(context, intOutputs, RegisterType.Int);

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace ChocolArm64.Translation
{
class LocalAlloc
class RegisterUsage
{
public const long CallerSavedIntRegistersMask = 0x7fL << 9;
public const long PStateNzcvFlagsMask = 0xfL << 60;
@ -23,31 +23,30 @@ namespace ChocolArm64.Translation
_cmnOutputs = new Dictionary<ILBlock, long>();
}
public PathIo(ILBlock root, long inputs, long outputs) : this()
public void Set(ILBlock entry, long inputs, long outputs)
{
Set(root, inputs, outputs);
}
public void Set(ILBlock root, long inputs, long outputs)
{
if (!_allInputs.TryAdd(root, inputs))
if (!_allInputs.TryAdd(entry, inputs))
{
_allInputs[root] |= inputs;
_allInputs[entry] |= inputs;
}
if (!_cmnOutputs.TryAdd(root, outputs))
if (!_cmnOutputs.TryAdd(entry, outputs))
{
_cmnOutputs[root] &= outputs;
_cmnOutputs[entry] &= outputs;
}
_allOutputs |= outputs;
}
public long GetInputs(ILBlock root)
public long GetInputs(ILBlock entry)
{
if (_allInputs.TryGetValue(root, out long inputs))
if (_allInputs.TryGetValue(entry, out long inputs))
{
return inputs | (_allOutputs & ~_cmnOutputs[root]);
//We also need to read the registers that may not be written
//by all paths that can reach a exit point, to ensure that
//the local variable will not remain uninitialized depending
//on the flow path taken.
return inputs | (_allOutputs & ~_cmnOutputs[entry]);
}
return 0;
@ -62,9 +61,7 @@ namespace ChocolArm64.Translation
private Dictionary<ILBlock, PathIo> _intPaths;
private Dictionary<ILBlock, PathIo> _vecPaths;
private HashSet<ILBlock> _entryBlocks;
private struct BlockIo
private struct BlockIo : IEquatable<BlockIo>
{
public ILBlock Block { get; }
public ILBlock Entry { get; }
@ -104,6 +101,11 @@ namespace ChocolArm64.Translation
return false;
}
return Equals(other);
}
public bool Equals(BlockIo other)
{
return other.Block == Block &&
other.Entry == Entry &&
other.IntInputs == IntInputs &&
@ -128,12 +130,10 @@ namespace ChocolArm64.Translation
}
}
public LocalAlloc()
public RegisterUsage()
{
_intPaths = new Dictionary<ILBlock, PathIo>();
_vecPaths = new Dictionary<ILBlock, PathIo>();
_entryBlocks = new HashSet<ILBlock>();
}
public void BuildUses(ILBlock entry)
@ -144,7 +144,7 @@ namespace ChocolArm64.Translation
//When a block can be reached by more than one path, then the
//output from all paths needs to be set for this block, and
//only outputs present in all of the parent blocks can be considered
//when doing input elimination. Each block chain have a entry, that's where
//when doing input elimination. Each block chain has a entry, that's where
//the code starts executing. They are present on the subroutine start point,
//and on call return points too (address written to X30 by BL).
HashSet<BlockIo> visited = new HashSet<BlockIo>();
@ -159,8 +159,6 @@ namespace ChocolArm64.Translation
}
}
_entryBlocks.Add(entry);
Enqueue(new BlockIo(entry, entry));
while (unvisited.Count > 0)
@ -198,8 +196,6 @@ namespace ChocolArm64.Translation
if (retTarget)
{
blockIo = new BlockIo(block, block);
_entryBlocks.Add(block);
}
else
{
@ -227,16 +223,16 @@ namespace ChocolArm64.Translation
}
}
public long GetIntInputs(ILBlock root) => GetInputsImpl(root, _intPaths.Values);
public long GetVecInputs(ILBlock root) => GetInputsImpl(root, _vecPaths.Values);
public long GetIntInputs(ILBlock entry) => GetInputsImpl(entry, _intPaths.Values);
public long GetVecInputs(ILBlock entry) => GetInputsImpl(entry, _vecPaths.Values);
private long GetInputsImpl(ILBlock root, IEnumerable<PathIo> values)
private long GetInputsImpl(ILBlock entry, IEnumerable<PathIo> values)
{
long inputs = 0;
foreach (PathIo path in values)
{
inputs |= path.GetInputs(root);
inputs |= path.GetInputs(entry);
}
return inputs;
@ -250,11 +246,9 @@ namespace ChocolArm64.Translation
//TODO: ARM32 support.
if (isAarch64)
{
mask &= ~CallerSavedIntRegistersMask;
mask &= ~PStateNzcvFlagsMask;
mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask);
}
return mask;
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Translation
{
enum IoType
enum VarType
{
Arg,
Flag,