From 36e8e074c90f11480389560e3f019a161f82efbe Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 10 Dec 2018 22:58:52 -0200 Subject: Misc. CPU improvements (#519) * Fix and simplify TranslatorCache * Fix some assignment alignments, remove some unused usings * Changes to ILEmitter, separate it from ILEmitterCtx * Rename ILEmitter to ILMethodBuilder * Rename LdrLit and *_Fix opcodes * Revert TranslatorCache impl to the more performant one, fix a few issues with it * Allow EmitOpCode to be called even after everything has been emitted * Make Emit and AdvanceOpCode private, simplify it a bit now that it starts emiting from the entry point * Remove unneeded temp use * Add missing exit call on TestExclusive * Use better hash * Implement the == and != operators --- ChocolArm64/Translation/ILMethodBuilder.cs | 144 +++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 ChocolArm64/Translation/ILMethodBuilder.cs (limited to 'ChocolArm64/Translation/ILMethodBuilder.cs') diff --git a/ChocolArm64/Translation/ILMethodBuilder.cs b/ChocolArm64/Translation/ILMethodBuilder.cs new file mode 100644 index 00000000..70d9a2db --- /dev/null +++ b/ChocolArm64/Translation/ILMethodBuilder.cs @@ -0,0 +1,144 @@ +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using System.Runtime.Intrinsics; + +namespace ChocolArm64.Translation +{ + class ILMethodBuilder + { + public LocalAlloc LocalAlloc { get; private set; } + + public ILGenerator Generator { get; private set; } + + private Dictionary _locals; + + private ILBlock[] _ilBlocks; + + private string _subName; + + private int _localsCount; + + public ILMethodBuilder(ILBlock[] ilBlocks, string subName) + { + _ilBlocks = ilBlocks; + _subName = subName; + } + + public TranslatedSub GetSubroutine() + { + LocalAlloc = new LocalAlloc(_ilBlocks, _ilBlocks[0]); + + List subArgs = new List(); + + void SetArgs(long inputs, RegisterType baseType) + { + for (int bit = 0; bit < 64; bit++) + { + long mask = 1L << bit; + + if ((inputs & mask) != 0) + { + subArgs.Add(GetRegFromBit(bit, baseType)); + } + } + } + + SetArgs(LocalAlloc.GetIntInputs(_ilBlocks[0]), RegisterType.Int); + SetArgs(LocalAlloc.GetVecInputs(_ilBlocks[0]), RegisterType.Vector); + + DynamicMethod method = new DynamicMethod(_subName, typeof(long), GetArgumentTypes(subArgs)); + + Generator = method.GetILGenerator(); + + TranslatedSub subroutine = new TranslatedSub(method, subArgs); + + int argsStart = TranslatedSub.FixedArgTypes.Length; + + _locals = new Dictionary(); + + _localsCount = 0; + + for (int index = 0; index < subroutine.SubArgs.Count; index++) + { + Register reg = subroutine.SubArgs[index]; + + Generator.EmitLdarg(index + argsStart); + Generator.EmitStloc(GetLocalIndex(reg)); + } + + foreach (ILBlock ilBlock in _ilBlocks) + { + ilBlock.Emit(this); + } + + return subroutine; + } + + private Type[] GetArgumentTypes(IList Params) + { + Type[] fixedArgs = TranslatedSub.FixedArgTypes; + + Type[] output = new Type[Params.Count + fixedArgs.Length]; + + fixedArgs.CopyTo(output, 0); + + int typeIdx = fixedArgs.Length; + + for (int index = 0; index < Params.Count; index++) + { + output[typeIdx++] = GetFieldType(Params[index].Type); + } + + return output; + } + + public int GetLocalIndex(Register reg) + { + if (!_locals.TryGetValue(reg, out int index)) + { + Generator.DeclareLocal(GetFieldType(reg.Type)); + + index = _localsCount++; + + _locals.Add(reg, index); + } + + return index; + } + + private static Type GetFieldType(RegisterType regType) + { + switch (regType) + { + case RegisterType.Flag: return typeof(bool); + case RegisterType.Int: return typeof(ulong); + case RegisterType.Vector: return typeof(Vector128); + } + + throw new ArgumentException(nameof(regType)); + } + + public static Register GetRegFromBit(int bit, RegisterType baseType) + { + if (bit < 32) + { + return new Register(bit, baseType); + } + else if (baseType == RegisterType.Int) + { + return new Register(bit & 0x1f, RegisterType.Flag); + } + else + { + throw new ArgumentOutOfRangeException(nameof(bit)); + } + } + + public static bool IsRegIndex(int index) + { + return (uint)index < 32; + } + } +} \ No newline at end of file -- cgit v1.2.3