using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Anonymus.x86
{
public static class x86Extensions
{
public static bool DontUseThisVar(this ExpressionNode Self)
{
var Data = Self.ArchData as x86NodeData;
if (Data == null) return false;
if (Data.Output is x86PostCalcedPosition)
{
var AssignPos = Data.Output as x86AssignVarPos;
if (!(AssignPos.Position is x86MemPosition))
return false;
var AData = AssignPos.AssignNode.ArchData as x86NodeData;
AData.DontUseCount++;
if (AData.DontUseCount >= 2)
{
AData.CanUseAssignVar_Calced = true;
AData.CanUseAssignVar = false;
return true;
}
}
return false;
}
public static Identifier GetId(this ExpressionNode Self)
{
if (Self is IdExpressionNode)
{
var RId = Self as IdExpressionNode;
return RId.Id;
}
var Data = Self.ArchData as x86NodeData;
if (Data != null)
{
var Pos = Data.Output as x86AssignVarPos;
if (Pos != null) return Pos.AssignVar;
}
return null;
}
public static bool SamePosition(this ExpressionNode Self, ExpressionNode Node, bool Size = true)
{
var SelfId = Self.GetId();
if (SelfId == Node.GetId() && SelfId != null)
return true;
var S = Self.GetPosition();
var N = Node.GetPosition();
if (S == null || N == null) return false;
else return S.IsEqual(N, Size);
}
public static x86DataPosition GetPosition(this ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
if (Data == null) return null;
if (Data.Output is x86PostCalcedPosition)
{
var Pos = Data.Output as x86PostCalcedPosition;
return Pos.Position.Copy(Node.Type.Size);
}
else
{
return Data.Output;
}
}
public static void IncRegs(this ExpressionNode Node, int Count = 1)
{
var Data = Node.ArchData as x86NodeData;
if (Data.NewScope) return;
if (Data.Index != -1) Data.Index += Count;
foreach (var e in Node.EnumChildren)
IncRegs(e, Count);
}
public static bool IsMem(this ExpressionNode Node, x86Architecture Arch)
{
var Data = Node.ArchData as x86NodeData;
var RIdNode = Node as IdExpressionNode;
if (RIdNode != null)
{
var Id = RIdNode.Id;
return Id.ArchData is x86MemPosition;
}
if (Node is ConstExpressionNode)
return false;
if (Node is LinkingNode)
{
var LNode = Node as LinkingNode;
var Linked = LNode.LinkedNode;
return Linked.ArchData is x86MemPosition;
}
var OpNode = Node as OpExpressionNode;
if (OpNode != null)
{
var Op = OpNode.Operator;
if (Op == Operator.Member) return true;
if (Op == Operator.Index) return true;
if (Op == Operator.Assignment)
return OpNode.Children[0].IsMem(Arch);
if (Op == Operator.Call)
{
if (Node.Type is ValueType) return true;
}
}
//-----------------------------------------------------
var Pos = Node.GetPosition();
if (Pos is x86MemPosition) return true;
if (Pos is x86MultiPosition) return (Pos as x86MultiPosition).HasMemPart();
return false;
}
public static bool NeedTmpReg(x86DataPosition Dst, x86DataPosition Src)
{
if (Dst is x86MemPosition && Src is x86MemPosition)
return true;
var D = Dst as x86MultiPosition;
var S = Src as x86MultiPosition;
if (D == null || S == null) return false;
var MLen = D.Positions.Length;
if (S.Positions.Length < MLen)
MLen = S.Positions.Length;
for (var i = 0; i < MLen; i++)
if (D.Positions[i] is x86MemPosition && S.Positions[i] is x86MemPosition)
return true;
return false;
}
public static bool NeedTmpReg(this ExpressionNode Self, x86Architecture Arch, x86DataPosition Src)
{
var SelfData = Self.ArchData as x86NodeData;
if (SelfData.Output is x86MultiPosition && Src is x86MultiPosition)
return NeedTmpReg(SelfData.Output, Src);
var SrcMem = Src is x86MemPosition;
if (Src is x86MultiPosition)
{
var MSrc = Src as x86MultiPosition;
SrcMem = MSrc.HasMemPart();
}
return SrcMem && Self.IsMem(Arch);
}
public static bool NeedTmpReg(this ExpressionNode Self, x86Architecture Arch, ExpressionNode Node)
{
var SelfData = Self.ArchData as x86NodeData;
var NodeData = Node.ArchData as x86NodeData;
if (SelfData.Output is x86MultiPosition && NodeData.Output is x86MultiPosition)
return NeedTmpReg(SelfData.Output, NodeData.Output);
return Self.IsMem(Arch) && Node.IsMem(Arch);
}
public static bool _CanUseAssignVar(this ExpressionNode Node, Identifier AssignVar)
{
var Used = false;
foreach (var e in Node.EnumChildren)
{
if (!Used && e.DataRegUsed()) Used = true;
else if (Used && e.IdUsed(AssignVar)) return false;
if (!e._CanUseAssignVar(AssignVar)) return false;
}
return true;
}
public static bool CanUseDataPosNoSave(this ExpressionNode Node, Type T, int Index)
{
var Data = Node.ArchData as x86NodeData;
if (T.Size < Node.Type.Size && Data.Index == Index) return false;
foreach (var e in Node.EnumChildren)
if (!e.CanUseDataPosNoSave(T, Index)) return false;
return true;
}
public static bool CanUseDataPos(this ExpressionNode Node, Type T, int Index)
{
var Data = Node.ArchData as x86NodeData;
if (Data.CanUseAssignVar_Calced)
return Data.CanUseAssignVar;
var RetValue = Node.CanUseDataPosNoSave(T, Index);
Data.CanUseAssignVar_Calced = true;
Data.CanUseAssignVar = RetValue;
return RetValue;
}
public static bool CanUseAssignVar(this ExpressionNode Node, Variable Var, x86RegList CantBe, int Index)
{
var Data = Node.ArchData as x86NodeData;
if (Data.CanUseAssignVar_Calced)
return Data.CanUseAssignVar;
var RetValue = true;
if (!Node.CanUseDataPosNoSave(Var.Type, Index)) RetValue = false;
else if (!Node._CanUseAssignVar(Var)) RetValue = false;
if (RetValue && CantBe != null)
{
var RegPos = Var.ArchData as x86RegPosition;
if (RegPos != null && CantBe[RegPos.Index] > 0) RetValue = false;
}
Data.CanUseAssignVar_Calced = true;
Data.CanUseAssignVar = RetValue;
return RetValue;
}
public static bool DataRegUsed(this ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
if (Data.Index != -1) return true;
foreach (var e in Node.EnumChildren)
if (e.DataRegUsed()) return true;
return false;
}
public static void GetUsed(this ExpressionNode Node, x86DataAllocator Allocator, bool Root = true)
{
var Data = Node.ArchData as x86NodeData;
var Scope = Data.Scope;
if (Data.UsedRegs != null) Allocator.UsedRegs.SetUsed(Data.UsedRegs);
if (Data.NewScope) Allocator.SetUsed(Scope.Allocator);
else if (Root) throw new Exception("ERROR");
foreach (var e in Node.EnumChildren)
e.GetUsed(Allocator, false);
}
}
[Flags]
public enum x86DataCalcPos
{
Memory = 1,
GeneralReg = 2,
SSEReg = 4,
GRegMem = GeneralReg | Memory,
SSEMem = SSEReg | Memory,
}
public class x86NodeData
{
public bool NewScope;
public int MulBy = 1;
public int FPUItemsOnStack = 0;
public int UsedFPUStack = 0;
public int Index = int.MaxValue;
public x86DataCalcPos DataCalcPos = x86DataCalcPos.GRegMem;
public x86DataPosition Input;
public x86DataPosition Output;
public x86RegList UsedRegs;
public x86RegList CantBe;
public x86ExprScope Scope;
public x86RegList PreAllocate;
// Assign OpNode
public bool CanUseAssignVar_Calced = false;
public bool CanUseAssignVar;
public int DontUseCount;
// Root Data
public List<x86ExprScope> AllScopes;
public x86RegList AllUsedRegs;
public x86NodeData(bool NewScope = false)
{
this.NewScope = NewScope;
}
public x86NodeData Copy()
{
var CRegs = CantBe != null ? CantBe.Copy() : null;
var Ret = new x86NodeData(NewScope);
Ret.CantBe = CRegs;
return Ret;
}
}
public class x86LinkedNodeData
{
public x86DataPosition Specified;
public x86DataPosition Position;
public x86LinkedNodeData(x86DataPosition Specified)
{
this.Specified = Specified;
}
}
public class x86ExprDataPos
{
public x86DataPosition DataPos;
public x86RegList CantBe;
public int MinSize = 0;
public int MinAlign = 0;
public x86DataCalcPos DataCalcPos = x86DataCalcPos.GRegMem;
public x86ExprDataPos(int RegCount)
{
CantBe = new x86RegList(RegCount);
}
}
public class x86ExprScope
{
public x86Architecture Arch;
public x86ExprScope Parent;
public List<x86ExprScope> Children = new List<x86ExprScope>();
public int NeededStack = 0;
public x86DataAllocator PreAllocated;
public x86DataAllocator Allocator;
public bool NeedSSETmpReg = false;
public bool NeedTmpReg = false;
public bool NeedIndexReg = false;
public int NeedTmpMem = 0;
public x86DataPosition TmpReg;
public x86DataPosition IndexReg;
public x86DataPosition SSETmpReg;
public x86DataPosition TmpMem;
public Dictionary<int, x86ExprDataPos> DataPositions =
new Dictionary<int, x86ExprDataPos>();
public void SetUsed(x86DataPosition Pos, bool Rec = true)
{
Allocator.SetUsed(Pos);
if (Rec)
{
foreach (var e in Children)
e.SetUsed(Pos, true);
}
}
public void NewDataPosition(ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
Data.Scope = this;
var Index = Data.Index;
if (Index != -1)
{
var Pos = this[Index];
if (Pos != null)
{
if (Data.CantBe != null)
{
if (Pos.CantBe == null) Pos.CantBe = Data.CantBe.Copy();
else Pos.CantBe.SetUsed(Data.CantBe);
}
}
else
{
Pos = new x86ExprDataPos(Arch.RegCount);
if (Data.CantBe != null)
Pos.CantBe = Data.CantBe.Copy();
DataPositions.Add(Index, Pos);
}
var Size = Node.Type.Size;
var Align = Arch.GetAlign(Node.Type);
if (Pos.MinSize < Size) Pos.MinSize = Size;
if (Pos.MinAlign < Align) Pos.MinAlign = Align;
Pos.DataCalcPos &= Data.DataCalcPos;
}
}
public void Reset(bool Rec = true)
{
foreach (var e in DataPositions.Keys)
DataPositions[e].DataPos = null;
if (PreAllocated != null)
Allocator.Set(PreAllocated);
else Allocator.Reset();
TmpReg = null;
IndexReg = null;
if (Rec)
{
foreach (var e in Children)
e.Reset(true);
}
}
public x86ExprScope(x86ExprScope Parent, IdContainer Container)
{
this.Arch = Container.State.Arch as x86Architecture;
this.Allocator = new x86DataAllocator(Container);
this.Parent = Parent;
}
public x86ExprDataPos this[int a]
{
get
{
x86ExprDataPos Ret;
if (!DataPositions.TryGetValue(a, out Ret))
return null;
return Ret;
}
}
public x86DataPosition AllocData(x86ExprDataPos P, bool Strict = true)
{
if (P.DataPos == null)
{
var CP = P.DataCalcPos;
if (!Strict) CP |= x86DataCalcPos.Memory;
P.DataPos = Allocator.Alloc(P.MinSize, P.MinAlign, CP, P.CantBe);
}
return P.DataPos;
}
public x86DataPosition AllocData(int Index, bool Strict = true)
{
var P = this[Index];
if (P == null) throw new Exception("ERROR");
return AllocData(P, Strict);
}
public x86DataPosition AllocData(int Index, int Size, bool Strict = true)
{
return AllocData(Index, Strict).Copy(Size);
}
public void AllocTmpRegs()
{
var R = Arch.RegSize;
if (NeedTmpMem > 0) TmpMem = Allocator.Alloc(NeedTmpMem, NeedTmpMem, x86DataCalcPos.Memory);
if (NeedTmpReg) TmpReg = Allocator.Alloc(R, R, x86DataCalcPos.GeneralReg);
if (NeedIndexReg) IndexReg = Allocator.Alloc(R, R, x86DataCalcPos.GeneralReg);
if (NeedSSETmpReg) SSETmpReg = Allocator.Alloc(16, 16, x86DataCalcPos.SSEReg);
}
}
public class x86DataPosCalcer
{
public CompilerState State;
public ExpressionNode ExprNode;
public x86Architecture Arch;
public IdContainer Container;
public x86FuncScopeNode FuncScope;
public x86DataPosCalcer(IdContainer Container, CompilerState State, ExpressionNode ExprNode)
{
this.State = State;
this.ExprNode = ExprNode;
this.Arch = State.Arch as x86Architecture;
this.Container = Container;
this.FuncScope = Container.FuncScope as x86FuncScopeNode;
}
public void Calc()
{
var Data = ExprNode.ArchData as x86NodeData;
Data.Scope.Reset();
Init(ExprNode);
PreCalc(ExprNode);
CalcLinkedNodes(ExprNode);
CalcRec(ExprNode);
var IdArchData = Container.ArchData as x86IdContainerData;
var IdAllocator = IdArchData.Allocator;
IdAllocator.UsedRegs.SetUsed(Data.AllUsedRegs);
foreach (var e in Data.AllScopes)
IdAllocator.SetUsed(e.Allocator);
}
private void Init(ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
var Scope = Data.Scope;
//------------------------------------------------------------
Variable Var = null;
if (Node.GetAssignVar(ref Var) && Var != null)
{
var OpNode = Node as OpExpressionNode;
var Ch1Data = OpNode.Children[1].ArchData as x86NodeData;
var Index = Ch1Data.Index != -1 ? Ch1Data.Index : 0;
var D = Scope[Index];
if (D != null && Node.CanUseAssignVar(Var, D.CantBe, Index))
{
D.DataPos = new x86AssignVarPos(Arch, Var, Node);
Data.DontUseCount = 0;
if (Var.ArchData != null)
{
var AVarPos = Var.ArchData as x86DataPosition;
Scope.Allocator.UsedRegs.SetUsed(AVarPos.GetRegs());
}
}
}
else if (Data.Input != null)
{
var D = Scope[0];
if (D != null && D.DataCalcPos.HasFlag(x86DataCalcPos.GeneralReg))
{
var I = Data.Input;
D.DataPos = I;
Scope.Allocator.UsedRegs.SetUsed(I.GetRegs());
}
}
//------------------------------------------------------------
if (Node.LinkedNodes != null)
{
foreach (var LNode in Node.LinkedNodes)
{
var LData = LNode.ArchData as x86LinkedNodeData;
LData.Position = null;
var Linked = LNode.Node;
var LinkedNData = Linked.ArchData as x86NodeData;
var LScope = LinkedNData.Scope;
var Index = LinkedNData.Index != -1 ? LinkedNData.Index : 0;
var ExprPos = LScope[Index];
if (ExprPos != null && Linked.CanUseDataPos(Linked.Type, Index))
{
ExprPos.DataPos = new x86LinkedNodePosition(Arch, LNode);
LinkedNData.DontUseCount = 0;
}
}
}
if (Data.NewScope) Scope.AllocTmpRegs();
foreach (var Ch in Node.EnumChildren)
Init(Ch);
}
private void PreCalc(ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
var Scope = Data.Scope;
if (Data.NewScope)
{
foreach (var Pos in Scope.DataPositions.Values)
if (!Pos.DataCalcPos.HasFlag(x86DataCalcPos.Memory))
Scope.AllocData(Pos);
}
foreach (var Ch in Node.EnumChildren)
PreCalc(Ch);
}
private void CalcLinkedNodes(ExpressionNode Node, x86DataAllocator Allocator = null)
{
var Data = Node.ArchData as x86NodeData;
var Scope = Data.Scope;
var AllocatorCopy = (x86DataAllocator)null;
if (Data.NewScope)
{
Allocator = new x86DataAllocator(Container);
Allocator.SetUsed(Scope.Allocator);
}
if (Node.LinkedNodes != null)
{
AllocatorCopy = Allocator.Copy();
for (var i = Node.LinkedNodes.Count - 1; i >= 0; i--)
{
var LNode = Node.LinkedNodes[i];
var LData = LNode.ArchData as x86LinkedNodeData;
var Linked = LNode.Node;
var LinkedData = Linked.ArchData as x86NodeData;
if (LData.Specified != null)
{
LData.Position = LData.Specified;
Allocator.SetUsed(LData.Specified);
}
else
{
var Out = LinkedData.Output;
if (Out != null && !(Out is x86PostCalcedPosition) && Allocator.IsFree(Out))
{
Allocator.SetUsed(LinkedData.Output);
LData.Position = LinkedData.Output;
}
else
{
LData.Position = Allocator.Alloc(Linked.Type);
}
Scope.SetUsed(LData.Position);
}
LNode.Node.GetUsed(Allocator);
}
}
foreach (var Ch in Node.EnumChildren)
CalcLinkedNodes(Ch, Allocator);
if (AllocatorCopy != null)
Allocator.Set(AllocatorCopy);
}
private void CalcRec(ExpressionNode Node)
{
var Data = Node.ArchData as x86NodeData;
var Scope = Data.Scope;
if (Data.Index != -1)
Data.Output = Scope.AllocData(Data.Index, Node.Type.Size, false);
var OpNode = Node as OpExpressionNode;
var Op = OpNode != null ? OpNode.Operator : Operator.Nothing;
if (Op == Operator.CreateTuple)
{
var Ch = OpNode.Children;
var Type = OpNode.Type as TupleType;
for (var i = 0; i < Ch.Count; i++)
{
var ChData = Ch[i].ArchData as x86NodeData;
var ChScope = ChData.Scope;
var MemVar = Type.Members[i] as MemberVariable;
var Index = Data.Index + i + 1;
var ExprPos = ChScope[Index];
if (ExprPos != null && Ch[i].CanUseDataPos(MemVar.Type, Index))
{
var Splitable = Data.Output as x86SplitablePosition;
var Part = Splitable.GetPart(MemVar.Offset, MemVar.Type.Size);
ExprPos.DataPos = Part;
}
}
}
foreach (var Ch in Node.EnumChildren)
CalcRec(Ch);
}
bool ChkMem2Mem_Recheck;
int ChkMem2Mem_Recheck_Index;
public bool ChkMem2Mem()
{
var Ret = true;
ChkMem2Mem_Recheck_Index = 0;
do
{
ChkMem2Mem_Recheck = false;
Ret = ChkMem2Mem_Rec(ExprNode);
ChkMem2Mem_Recheck_Index++;
}
while (ChkMem2Mem_Recheck && Ret);
return Ret;
}
bool ChkMem2Mem_Rec(ExpressionNode Node)
{
if (!ChkMem2Mem_Func(Node)) return false;
foreach (var Ch in Node.EnumChildren)
if (!ChkMem2Mem_Rec(Ch)) return false;
return true;
}
[Flags]
enum TmpRegAllocType
{
General = 1,
Index = 2,
SSE = 4,
Mem = 8,
}
bool ChkMem2Mem_Func(ExpressionNode Node)
{
var NeedMove = 0;
var RegType = TmpRegAllocType.General;
var DontUseAssignVar = false;
var Data = Node.ArchData as x86NodeData;
if (Node.LinkedNodes != null)
{
foreach (var e in Node.LinkedNodes)
if (e.Node.NeedTmpReg(Arch, e.ArchData as x86DataPosition))
{
NeedMove = e.Node.Type.Size;
if (NeedMove % 4 == 0 && NeedMove > Arch.RegSize)
RegType = TmpRegAllocType.SSE;
}
}
if (Node is CastExpressionNode)
{
var CastNode = Node as CastExpressionNode;
var Type = CastNode.Type;
var SrcNode = CastNode.Child;
if (Type is NonFltNumType)
{
if (SrcNode.Type is FloatType)
{
if (!CastNode.IsMem(Arch))
{
NeedMove = Type.Size;
RegType = TmpRegAllocType.Mem;
}
}
}
else if (Type is FloatType)
{
if (!SrcNode.IsMem(Arch))
{
NeedMove = SrcNode.Type.Size;
RegType = TmpRegAllocType.Mem;
}
}
if (Data.Index != -1 && !SrcNode.SamePosition(CastNode) && CastNode.NeedTmpReg(Arch, SrcNode))
{
NeedMove = SrcNode.Type.Size;
if (Type.Size == NeedMove && NeedMove % 4 == 0 && NeedMove > Arch.RegSize)
RegType = TmpRegAllocType.SSE;
}
}
else if (Node is OpExpressionNode)
{
var OpNode = Node as OpExpressionNode;
var Op = OpNode.Operator;
var Ch = OpNode.Children;
var Type = Ch.Count > 0 ? Ch[0].Type : null;
if (Op == Operator.CreateTuple)
{
if (Node.IsMem(Arch))
foreach (var e in Ch)
if (e.IsMem(Arch))
{
var S = e.Type.Size;
if (NeedMove < S) NeedMove = S;
if (S % 4 == 0 && S > Arch.RegSize)
RegType |= TmpRegAllocType.SSE;
else RegType |= TmpRegAllocType.General;
}
}
else if (Op == Operator.New)
{
NeedMove = Node.Type.Size;
if (NeedMove % 4 == 0 && NeedMove > Arch.RegSize)
RegType = TmpRegAllocType.SSE;
}
else if (Op == Operator.Multiply && Type.Size != 1)
{
if (Ch[0].IsMem(Arch))
{
NeedMove = Type.Size;
if (ChkMem2Mem_Recheck_Index == 0 && Ch[0].DontUseThisVar())
DontUseAssignVar = true;
}
}
else if (Op == Operator.Index)
{
if (Ch[0].IsMem(Arch))
{
NeedMove = Arch.RegSize;
RegType = TmpRegAllocType.Index;
if (ChkMem2Mem_Recheck_Index == 0 && Ch[0].DontUseThisVar())
DontUseAssignVar = true;
}
}
else if (Op == Operator.Member)
{
var RIdCh1 = Ch[1] as IdExpressionNode;
if (RIdCh1 != null && RIdCh1.Id is MemberFunction)
NeedMove = Arch.RegSize;
}
else if (Operators.IsRelEqualityOp(Op) || Operators.IsBitArithmOp(Op) || Op == Operator.Assignment)
{
if ((Op != Operator.Assignment || !Ch[0].SamePosition(Ch[1])) && !(Node.Type is FloatType))
if (Ch[0].NeedTmpReg(Arch, Ch[1]))
{
NeedMove = Type.Size;
if (Op == Operator.Assignment && NeedMove % 4 == 0 && NeedMove > Arch.RegSize)
RegType = TmpRegAllocType.SSE;
if (ChkMem2Mem_Recheck_Index == 0)
{
if (Ch[0].DontUseThisVar() || Ch[1].DontUseThisVar())
DontUseAssignVar = true;
}
}
}
}
if (NeedMove > 0)
{
if (ChkMem2Mem_Recheck_Index == 0)
{
if (DontUseAssignVar) return false;
else ChkMem2Mem_Recheck = true;
}
else
{
var Scope = Data.Scope;
if (RegType.HasFlag(TmpRegAllocType.Mem) && Scope.TmpMem == null)
{
Scope.NeedTmpMem = NeedMove;
return false;
}
if (RegType.HasFlag(TmpRegAllocType.General) && Scope.TmpReg == null)
{
Scope.NeedTmpReg = true;
return false;
}
if (RegType.HasFlag(TmpRegAllocType.Index) && Scope.IndexReg == null)
{
Scope.NeedIndexReg = true;
return false;
}
if (RegType.HasFlag(TmpRegAllocType.SSE) && Scope.SSETmpReg == null)
{
Scope.NeedSSETmpReg = true;
return false;
}
}
}
return true;
}
}
}