aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Translation/ILMethodBuilder.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-12-10 22:58:52 -0200
committerGitHub <noreply@github.com>2018-12-10 22:58:52 -0200
commit36e8e074c90f11480389560e3f019a161f82efbe (patch)
treea187c1702feba371ff9be1b71491efc3dfcf9ed8 /ChocolArm64/Translation/ILMethodBuilder.cs
parentf1529b1bc2bafbdadcf4d4643aa5716414097239 (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.cs144
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