187 lines
5 KiB
C#
187 lines
5 KiB
C#
|
using ChocolArm64.Decoder;
|
||
|
using ChocolArm64.State;
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Reflection.Emit;
|
||
|
|
||
|
namespace ChocolArm64.Translation
|
||
|
{
|
||
|
class AILEmitter
|
||
|
{
|
||
|
public ALocalAlloc LocalAlloc { get; private set; }
|
||
|
|
||
|
public ILGenerator Generator { get; private set; }
|
||
|
|
||
|
private Dictionary<ARegister, int> Locals;
|
||
|
|
||
|
private AILBlock[] ILBlocks;
|
||
|
|
||
|
private AILBlock Root;
|
||
|
|
||
|
private ATranslatedSub Subroutine;
|
||
|
|
||
|
private string SubName;
|
||
|
|
||
|
private int LocalsCount;
|
||
|
|
||
|
public AILEmitter(ABlock[] Graph, ABlock Root, string SubName)
|
||
|
{
|
||
|
this.SubName = SubName;
|
||
|
|
||
|
Locals = new Dictionary<ARegister, int>();
|
||
|
|
||
|
ILBlocks = new AILBlock[Graph.Length];
|
||
|
|
||
|
AILBlock GetBlock(int Index)
|
||
|
{
|
||
|
if (Index < 0 || Index >= ILBlocks.Length)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
if (ILBlocks[Index] == null)
|
||
|
{
|
||
|
ILBlocks[Index] = new AILBlock();
|
||
|
}
|
||
|
|
||
|
return ILBlocks[Index];
|
||
|
}
|
||
|
|
||
|
for (int Index = 0; Index < ILBlocks.Length; Index++)
|
||
|
{
|
||
|
AILBlock Block = GetBlock(Index);
|
||
|
|
||
|
Block.Next = GetBlock(Array.IndexOf(Graph, Graph[Index].Next));
|
||
|
Block.Branch = GetBlock(Array.IndexOf(Graph, Graph[Index].Branch));
|
||
|
}
|
||
|
|
||
|
this.Root = ILBlocks[Array.IndexOf(Graph, Root)];
|
||
|
}
|
||
|
|
||
|
public ATranslatedSub GetSubroutine()
|
||
|
{
|
||
|
LocalAlloc = new ALocalAlloc(ILBlocks, Root);
|
||
|
|
||
|
InitSubroutine();
|
||
|
InitLocals();
|
||
|
|
||
|
foreach (AILBlock ILBlock in ILBlocks)
|
||
|
{
|
||
|
ILBlock.Emit(this);
|
||
|
}
|
||
|
|
||
|
return Subroutine;
|
||
|
}
|
||
|
|
||
|
public AILBlock GetILBlock(int Index) => ILBlocks[Index];
|
||
|
|
||
|
private void InitLocals()
|
||
|
{
|
||
|
int ParamsStart = ATranslatedSub.FixedArgTypes.Length;
|
||
|
|
||
|
Locals = new Dictionary<ARegister, int>();
|
||
|
|
||
|
for (int Index = 0; Index < Subroutine.Params.Count; Index++)
|
||
|
{
|
||
|
ARegister Reg = Subroutine.Params[Index];
|
||
|
|
||
|
Generator.EmitLdarg(Index + ParamsStart);
|
||
|
Generator.EmitStloc(GetLocalIndex(Reg));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void InitSubroutine()
|
||
|
{
|
||
|
List<ARegister> Params = new List<ARegister>();
|
||
|
|
||
|
void SetParams(long Inputs, ARegisterType BaseType)
|
||
|
{
|
||
|
for (int Bit = 0; Bit < 64; Bit++)
|
||
|
{
|
||
|
long Mask = 1L << Bit;
|
||
|
|
||
|
if ((Inputs & Mask) != 0)
|
||
|
{
|
||
|
Params.Add(GetRegFromBit(Bit, BaseType));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetParams(LocalAlloc.GetIntInputs(Root), ARegisterType.Int);
|
||
|
SetParams(LocalAlloc.GetVecInputs(Root), ARegisterType.Vector);
|
||
|
|
||
|
DynamicMethod Mthd = new DynamicMethod(SubName, typeof(long), GetParamTypes(Params));
|
||
|
|
||
|
Generator = Mthd.GetILGenerator();
|
||
|
|
||
|
Subroutine = new ATranslatedSub(Mthd, Params);
|
||
|
}
|
||
|
|
||
|
private Type[] GetParamTypes(IList<ARegister> Params)
|
||
|
{
|
||
|
Type[] FixedArgs = ATranslatedSub.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(ARegister Reg)
|
||
|
{
|
||
|
if (!Locals.TryGetValue(Reg, out int Index))
|
||
|
{
|
||
|
Generator.DeclareLocal(GetLocalType(Reg));
|
||
|
|
||
|
Index = LocalsCount++;
|
||
|
|
||
|
Locals.Add(Reg, Index);
|
||
|
}
|
||
|
|
||
|
return Index;
|
||
|
}
|
||
|
|
||
|
public Type GetLocalType(ARegister Reg) => GetFieldType(Reg.Type);
|
||
|
|
||
|
public Type GetFieldType(ARegisterType RegType)
|
||
|
{
|
||
|
switch (RegType)
|
||
|
{
|
||
|
case ARegisterType.Flag: return typeof(bool);
|
||
|
case ARegisterType.Int: return typeof(ulong);
|
||
|
case ARegisterType.Vector: return typeof(AVec);
|
||
|
}
|
||
|
|
||
|
throw new ArgumentException(nameof(RegType));
|
||
|
}
|
||
|
|
||
|
public static ARegister GetRegFromBit(int Bit, ARegisterType BaseType)
|
||
|
{
|
||
|
if (Bit < 32)
|
||
|
{
|
||
|
return new ARegister(Bit, BaseType);
|
||
|
}
|
||
|
else if (BaseType == ARegisterType.Int)
|
||
|
{
|
||
|
return new ARegister(Bit & 0x1f, ARegisterType.Flag);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(Bit));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static bool IsRegIndex(int Index)
|
||
|
{
|
||
|
return Index >= 0 && Index < 32;
|
||
|
}
|
||
|
}
|
||
|
}
|