diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-12-10 22:58:52 -0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-10 22:58:52 -0200 |
| commit | 36e8e074c90f11480389560e3f019a161f82efbe (patch) | |
| tree | a187c1702feba371ff9be1b71491efc3dfcf9ed8 /ChocolArm64/Translation/ILMethodBuilder.cs | |
| parent | f1529b1bc2bafbdadcf4d4643aa5716414097239 (diff) | |
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
Diffstat (limited to 'ChocolArm64/Translation/ILMethodBuilder.cs')
| -rw-r--r-- | ChocolArm64/Translation/ILMethodBuilder.cs | 144 |
1 files changed, 144 insertions, 0 deletions
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<Register, int> _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<Register> subArgs = new List<Register>(); + + 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<Register, int>(); + + _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<Register> 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<float>); + } + + 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 |
