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) switch (ld.IoType)
{ {
case IoType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~_intAwOutputs; break; case VarType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~_intAwOutputs; break;
case IoType.Int: IntInputs |= (1L << ld.Index) & ~_intAwOutputs; break; case VarType.Int: IntInputs |= (1L << ld.Index) & ~_intAwOutputs; break;
case IoType.Vector: VecInputs |= (1L << ld.Index) & ~_vecAwOutputs; break; case VarType.Vector: VecInputs |= (1L << ld.Index) & ~_vecAwOutputs; break;
} }
} }
else if (emitter is ILOpCodeStore st && ILMethodBuilder.IsRegIndex(st.Index)) else if (emitter is ILOpCodeStore st && ILMethodBuilder.IsRegIndex(st.Index))
{ {
switch (st.IoType) switch (st.IoType)
{ {
case IoType.Flag: IntOutputs |= (1L << st.Index) << 32; break; case VarType.Flag: IntOutputs |= (1L << st.Index) << 32; break;
case IoType.Int: IntOutputs |= 1L << st.Index; break; case VarType.Int: IntOutputs |= 1L << st.Index; break;
case IoType.Vector: VecOutputs |= 1L << st.Index; break; case VarType.Vector: VecOutputs |= 1L << st.Index; break;
} }
} }
else if (emitter is ILOpCodeStoreState) else if (emitter is ILOpCodeStoreState)

View file

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

View file

@ -8,7 +8,10 @@ namespace ChocolArm64.Translation
{ {
class ILMethodBuilder 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; } public ILGenerator Generator { get; private set; }
@ -38,20 +41,20 @@ namespace ChocolArm64.Translation
public TranslatedSub GetSubroutine(TranslationTier tier) 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); DynamicMethod method = new DynamicMethod(_subName, typeof(long), TranslatedSub.FixedArgTypes);
Generator = method.GetILGenerator();
TranslatedSub subroutine = new TranslatedSub(method, tier); TranslatedSub subroutine = new TranslatedSub(method, tier);
_locals = new Dictionary<Register, int>(); _locals = new Dictionary<Register, int>();
_localsCount = 0; _localsCount = 0;
Generator = method.GetILGenerator();
foreach (ILBlock ilBlock in _ilBlocks) foreach (ILBlock ilBlock in _ilBlocks)
{ {
ilBlock.Emit(this); ilBlock.Emit(this);
@ -90,13 +93,13 @@ namespace ChocolArm64.Translation
public static Register GetRegFromBit(int bit, RegisterType baseType) public static Register GetRegFromBit(int bit, RegisterType baseType)
{ {
if (bit < 32) if (bit < RegsCount)
{ {
return new Register(bit, baseType); return new Register(bit, baseType);
} }
else if (baseType == RegisterType.Int) else if (baseType == RegisterType.Int)
{ {
return new Register(bit & 0x1f, RegisterType.Flag); return new Register(bit & RegsMask, RegisterType.Flag);
} }
else else
{ {
@ -106,7 +109,7 @@ namespace ChocolArm64.Translation
public static bool IsRegIndex(int index) 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 struct ILOpCode : IILEmit
{ {
private OpCode _ilOp; public OpCode ILOp { get; }
public ILOpCode(OpCode ilOp) public ILOpCode(OpCode ilOp)
{ {
_ilOp = ilOp; ILOp = ilOp;
} }
public void Emit(ILMethodBuilder context) 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 struct ILOpCodeBranch : IILEmit
{ {
private OpCode _ilOp; public OpCode ILOp { get; }
private ILLabel _label; public ILLabel Label { get; }
public ILOpCodeBranch(OpCode ilOp, ILLabel label) public ILOpCodeBranch(OpCode ilOp, ILLabel label)
{ {
_ilOp = ilOp; ILOp = ilOp;
_label = label; Label = label;
} }
public void Emit(ILMethodBuilder context) 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 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) public ILOpCodeCall(MethodInfo info, bool isVirtual)
{ {

View file

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

View file

@ -5,13 +5,13 @@ namespace ChocolArm64.Translation
{ {
struct ILOpCodeLoad : IILEmit 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; Index = index;
IoType = ioType; IoType = ioType;
@ -22,11 +22,11 @@ namespace ChocolArm64.Translation
{ {
switch (IoType) 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 VarType.Flag: EmitLdloc(context, Index, RegisterType.Flag); break;
case IoType.Int: EmitLdloc(context, Index, RegisterType.Int); break; case VarType.Int: EmitLdloc(context, Index, RegisterType.Int); break;
case IoType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break; case VarType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break;
} }
} }

View file

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

View file

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

View file

@ -2,16 +2,16 @@ namespace ChocolArm64.Translation
{ {
struct ILOpCodeLog : IILEmit struct ILOpCodeLog : IILEmit
{ {
private string _text; public string Text { get; }
public ILOpCodeLog(string text) public ILOpCodeLog(string text)
{ {
_text = text; Text = text;
} }
public void Emit(ILMethodBuilder context) 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 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; Index = index;
IoType = ioType; IoType = ioType;
@ -22,11 +22,11 @@ namespace ChocolArm64.Translation
{ {
switch (IoType) 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 VarType.Flag: EmitStloc(context, Index, RegisterType.Flag); break;
case IoType.Int: EmitStloc(context, Index, RegisterType.Int); break; case VarType.Int: EmitStloc(context, Index, RegisterType.Int); break;
case IoType.Vector: EmitStloc(context, Index, RegisterType.Vector); break; case VarType.Vector: EmitStloc(context, Index, RegisterType.Vector); break;
} }
} }

View file

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

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace ChocolArm64.Translation namespace ChocolArm64.Translation
{ {
class LocalAlloc class RegisterUsage
{ {
public const long CallerSavedIntRegistersMask = 0x7fL << 9; public const long CallerSavedIntRegistersMask = 0x7fL << 9;
public const long PStateNzcvFlagsMask = 0xfL << 60; public const long PStateNzcvFlagsMask = 0xfL << 60;
@ -23,31 +23,30 @@ namespace ChocolArm64.Translation
_cmnOutputs = new Dictionary<ILBlock, long>(); _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); if (!_allInputs.TryAdd(entry, inputs))
}
public void Set(ILBlock root, long inputs, long outputs)
{
if (!_allInputs.TryAdd(root, 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; _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; return 0;
@ -62,9 +61,7 @@ namespace ChocolArm64.Translation
private Dictionary<ILBlock, PathIo> _intPaths; private Dictionary<ILBlock, PathIo> _intPaths;
private Dictionary<ILBlock, PathIo> _vecPaths; private Dictionary<ILBlock, PathIo> _vecPaths;
private HashSet<ILBlock> _entryBlocks; private struct BlockIo : IEquatable<BlockIo>
private struct BlockIo
{ {
public ILBlock Block { get; } public ILBlock Block { get; }
public ILBlock Entry { get; } public ILBlock Entry { get; }
@ -104,6 +101,11 @@ namespace ChocolArm64.Translation
return false; return false;
} }
return Equals(other);
}
public bool Equals(BlockIo other)
{
return other.Block == Block && return other.Block == Block &&
other.Entry == Entry && other.Entry == Entry &&
other.IntInputs == IntInputs && other.IntInputs == IntInputs &&
@ -128,12 +130,10 @@ namespace ChocolArm64.Translation
} }
} }
public LocalAlloc() public RegisterUsage()
{ {
_intPaths = new Dictionary<ILBlock, PathIo>(); _intPaths = new Dictionary<ILBlock, PathIo>();
_vecPaths = new Dictionary<ILBlock, PathIo>(); _vecPaths = new Dictionary<ILBlock, PathIo>();
_entryBlocks = new HashSet<ILBlock>();
} }
public void BuildUses(ILBlock entry) 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 //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 //output from all paths needs to be set for this block, and
//only outputs present in all of the parent blocks can be considered //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, //the code starts executing. They are present on the subroutine start point,
//and on call return points too (address written to X30 by BL). //and on call return points too (address written to X30 by BL).
HashSet<BlockIo> visited = new HashSet<BlockIo>(); HashSet<BlockIo> visited = new HashSet<BlockIo>();
@ -159,8 +159,6 @@ namespace ChocolArm64.Translation
} }
} }
_entryBlocks.Add(entry);
Enqueue(new BlockIo(entry, entry)); Enqueue(new BlockIo(entry, entry));
while (unvisited.Count > 0) while (unvisited.Count > 0)
@ -198,8 +196,6 @@ namespace ChocolArm64.Translation
if (retTarget) if (retTarget)
{ {
blockIo = new BlockIo(block, block); blockIo = new BlockIo(block, block);
_entryBlocks.Add(block);
} }
else else
{ {
@ -227,16 +223,16 @@ namespace ChocolArm64.Translation
} }
} }
public long GetIntInputs(ILBlock root) => GetInputsImpl(root, _intPaths.Values); public long GetIntInputs(ILBlock entry) => GetInputsImpl(entry, _intPaths.Values);
public long GetVecInputs(ILBlock root) => GetInputsImpl(root, _vecPaths.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; long inputs = 0;
foreach (PathIo path in values) foreach (PathIo path in values)
{ {
inputs |= path.GetInputs(root); inputs |= path.GetInputs(entry);
} }
return inputs; return inputs;
@ -250,11 +246,9 @@ namespace ChocolArm64.Translation
//TODO: ARM32 support. //TODO: ARM32 support.
if (isAarch64) if (isAarch64)
{ {
mask &= ~CallerSavedIntRegistersMask; mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask);
mask &= ~PStateNzcvFlagsMask;
} }
return mask; return mask;
} }

View file

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