diff --git a/ChocolArm64/Translation/ILBlock.cs b/ChocolArm64/Translation/ILBlock.cs index 69b89e3bd8..25183e4bd4 100644 --- a/ChocolArm64/Translation/ILBlock.cs +++ b/ChocolArm64/Translation/ILBlock.cs @@ -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) diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index 1470325d4f..8875bf30eb 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -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 _branchOps = new Dictionary() @@ -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)); } diff --git a/ChocolArm64/Translation/ILMethodBuilder.cs b/ChocolArm64/Translation/ILMethodBuilder.cs index c1535380bc..15c61d9db5 100644 --- a/ChocolArm64/Translation/ILMethodBuilder.cs +++ b/ChocolArm64/Translation/ILMethodBuilder.cs @@ -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(); _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; } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCode.cs b/ChocolArm64/Translation/ILOpCode.cs index 4021603c01..486452820d 100644 --- a/ChocolArm64/Translation/ILOpCode.cs +++ b/ChocolArm64/Translation/ILOpCode.cs @@ -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); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeBranch.cs b/ChocolArm64/Translation/ILOpCodeBranch.cs index 93c63130f5..9d4e40fa9d 100644 --- a/ChocolArm64/Translation/ILOpCodeBranch.cs +++ b/ChocolArm64/Translation/ILOpCodeBranch.cs @@ -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)); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeCall.cs b/ChocolArm64/Translation/ILOpCodeCall.cs index c046aeeb75..dc20417a9a 100644 --- a/ChocolArm64/Translation/ILOpCodeCall.cs +++ b/ChocolArm64/Translation/ILOpCodeCall.cs @@ -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) { diff --git a/ChocolArm64/Translation/ILOpCodeConst.cs b/ChocolArm64/Translation/ILOpCodeConst.cs index 2aaf8676ee..cd3b58ff04 100644 --- a/ChocolArm64/Translation/ILOpCodeConst.cs +++ b/ChocolArm64/Translation/ILOpCodeConst.cs @@ -16,6 +16,8 @@ namespace ChocolArm64.Translation private ImmVal _value; + public long Value => _value.I8; + private enum ConstType { Int32, diff --git a/ChocolArm64/Translation/ILOpCodeLoad.cs b/ChocolArm64/Translation/ILOpCodeLoad.cs index c31e06bbd9..5f4e5dad34 100644 --- a/ChocolArm64/Translation/ILOpCodeLoad.cs +++ b/ChocolArm64/Translation/ILOpCodeLoad.cs @@ -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; } } diff --git a/ChocolArm64/Translation/ILOpCodeLoadField.cs b/ChocolArm64/Translation/ILOpCodeLoadField.cs index abcd37c348..f0507ac226 100644 --- a/ChocolArm64/Translation/ILOpCodeLoadField.cs +++ b/ChocolArm64/Translation/ILOpCodeLoadField.cs @@ -5,7 +5,7 @@ namespace ChocolArm64.Translation { struct ILOpCodeLoadField : IILEmit { - public FieldInfo Info { get; private set; } + public FieldInfo Info { get; } public ILOpCodeLoadField(FieldInfo info) { diff --git a/ChocolArm64/Translation/ILOpCodeLoadState.cs b/ChocolArm64/Translation/ILOpCodeLoadState.cs index e829b8e222..c23dc94329 100644 --- a/ChocolArm64/Translation/ILOpCodeLoadState.cs +++ b/ChocolArm64/Translation/ILOpCodeLoadState.cs @@ -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); diff --git a/ChocolArm64/Translation/ILOpCodeLog.cs b/ChocolArm64/Translation/ILOpCodeLog.cs index ebb042b596..53846f927e 100644 --- a/ChocolArm64/Translation/ILOpCodeLog.cs +++ b/ChocolArm64/Translation/ILOpCodeLog.cs @@ -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); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeStore.cs b/ChocolArm64/Translation/ILOpCodeStore.cs index 17a6259c6f..6d562add11 100644 --- a/ChocolArm64/Translation/ILOpCodeStore.cs +++ b/ChocolArm64/Translation/ILOpCodeStore.cs @@ -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; } } diff --git a/ChocolArm64/Translation/ILOpCodeStoreState.cs b/ChocolArm64/Translation/ILOpCodeStoreState.cs index 02639611e0..d22410e50a 100644 --- a/ChocolArm64/Translation/ILOpCodeStoreState.cs +++ b/ChocolArm64/Translation/ILOpCodeStoreState.cs @@ -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); diff --git a/ChocolArm64/Translation/LocalAlloc.cs b/ChocolArm64/Translation/RegisterUsage.cs similarity index 84% rename from ChocolArm64/Translation/LocalAlloc.cs rename to ChocolArm64/Translation/RegisterUsage.cs index 7f8d15367c..999d6d065c 100644 --- a/ChocolArm64/Translation/LocalAlloc.cs +++ b/ChocolArm64/Translation/RegisterUsage.cs @@ -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(); } - 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 _intPaths; private Dictionary _vecPaths; - private HashSet _entryBlocks; - - private struct BlockIo + private struct BlockIo : IEquatable { 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(); _vecPaths = new Dictionary(); - - _entryBlocks = new HashSet(); } 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 visited = new HashSet(); @@ -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 values) + private long GetInputsImpl(ILBlock entry, IEnumerable 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; } diff --git a/ChocolArm64/Translation/IoType.cs b/ChocolArm64/Translation/VarType.cs similarity index 85% rename from ChocolArm64/Translation/IoType.cs rename to ChocolArm64/Translation/VarType.cs index c7710e0c67..d671575e98 100644 --- a/ChocolArm64/Translation/IoType.cs +++ b/ChocolArm64/Translation/VarType.cs @@ -1,6 +1,6 @@ namespace ChocolArm64.Translation { - enum IoType + enum VarType { Arg, Flag,