Click here to Skip to main content
15,896,528 members
Articles / High Performance Computing / Vectorization

Bird Programming Language: Part 1

Rate me:
Please Sign up or sign in to vote.
4.92/5 (129 votes)
1 Jan 2013GPL312 min read 385.1K   2.7K   153  
A new general purpose language that aims to be fast, high level and simple to use.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Anonymus.x86
{
	public partial class x86PlugIn : ExprPlugIn
	{
		public x86Architecture Arch;
		public List<x86ExprScope> AllScopes;
		public x86RegList AllUsedRegs;

        public ExpressionNode CreateLinkingNode(ExpressionNode Node, ExpressionNode Parent, x86DataPosition AssignPos)
        {
            if (Parent.LinkedNodes == null)
                Parent.LinkedNodes = new List<LinkedExprNode>();

            var Linked = new LinkedExprNode(Node);
            Linked.ArchData = new x86LinkedNodeData(AssignPos);
            Parent.LinkedNodes.Add(Linked);
            Node = Root.NewNode(new LinkingNode(Linked, Parent.Code));
            return Node;
        }

		public void CalcExprScopes(ExpressionNode Node)
		{
			AllScopes = new List<x86ExprScope>() { };
			AllUsedRegs = new x86RegList(Arch.RegCount);
			CalcExprScopes_Rec(Node, null);

			var Data = Node.ArchData as x86NodeData;
			Data.AllScopes = AllScopes;
			Data.AllUsedRegs = AllUsedRegs;
		}

		public void CalcExprScopes_Rec(ExpressionNode Node, x86ExprScope Scope)
		{
			var Data = Node.ArchData as x86NodeData;
			if (Data.UsedRegs != null) AllUsedRegs.SetUsed(Data.UsedRegs);

			if (Data.NewScope)
			{
				var NewScope = new x86ExprScope(Scope, Container);
                if (Scope != null) Scope.Children.Add(NewScope);
                AllScopes.Add(NewScope);
                Scope = NewScope;
			}

			if (Node.LinkedNodes != null)
			{
				foreach (var e in Node.LinkedNodes)
				{
					var LData = e.ArchData as x86LinkedNodeData;
					if (LData.Specified != null)
					{
						if (Scope.PreAllocated == null)
							Scope.PreAllocated = new x86DataAllocator(Container);

						Scope.PreAllocated.SetUsed(LData.Specified);
					}
				}
			}

			if (Data.PreAllocate != null)
			{
				if (Scope.PreAllocated == null)
					Scope.PreAllocated = new x86DataAllocator(Container);

				Scope.PreAllocated.UsedRegs.SetUsed(Data.PreAllocate);
			}

			Scope.NewDataPosition(Node);
			foreach (var e in Node.EnumChildren)
				CalcExprScopes_Rec(e, Scope);
		}

		public x86PlugIn(x86Architecture Arch, IdContainer Container)
			: base(Container)
		{
			this.Arch = Arch;
		}

		public override PlugInRes End(ref ExpressionNode Node)
        {
            var Data = Node.ArchData as x86NodeData;
            Data.NewScope = true;

            var OpNode = Node as OpExpressionNode;
            if (OpNode != null && OpNode.Operator == Operator.CreateTuple)
                Data.Index = -1;

			CalcExprScopes(Node);
			return PlugInRes.Succeeded;
		}

		public PlugInRes NewOpNode_NonFloat(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;
			var Type = Ch[0].Type;

			//--------------------------------------------------------------------------------------
			if (Operators.IsMathsOp(Op))
			{
				if (Op == Operator.Abs)
				{
					var LinkedNode = new LinkedExprNode(Ch[0]);

					var Zero = Root.NewNode(Expressions.GetIntValue(Container, 0, Node.Code));
					if (Zero == null) return PlugInRes.Failed;
					var CmpWith = Root.NewNode(new LinkingNode(LinkedNode, Node.Code));
					if (CmpWith == null) return PlugInRes.Failed;
					var CondCh = new List<ExpressionNode>() { Ch[0], Zero };
					var Cond = new OpExpressionNode(Operator.Less, CondCh, Node.Code);

					var Then = Root.NewNode(new LinkingNode(LinkedNode, Node.Code));
					if (Then == null) return PlugInRes.Failed;

					var Else = Root.NewNode(new LinkingNode(LinkedNode, Node.Code));
					if (Else == null) return PlugInRes.Failed;
					var ElseCh = new List<ExpressionNode>() { Else };
					Else = Root.NewNode(new OpExpressionNode(Operator.Neg, ElseCh, Node.Code));
					if (Else == null) return PlugInRes.Failed;

					var NewCh = new List<ExpressionNode>() { Cond, Then, Else };
					var Ret = new OpExpressionNode(Operator.Condition, NewCh, Node.Code);
					Ret.LinkedNodes = new List<LinkedExprNode>() { LinkedNode };
					Node = Root.NewNode(Ret);
					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else
				{
					Ch[0] = Root.NewNode(new CastExpressionNode(Node.Type, Ch[0], Node.Code));
					if (Ch[0] == null) return PlugInRes.Failed;
					return NewOpNode_Float(ref Node);
				}
			}

			//--------------------------------------------------------------------------------------
			if (Operators.IsShiftOp(Op))
			{
				if (Type.Size > Arch.RegSize)
				{
					var Func = (string)null;
					if (Op == Operator.ShiftLeft) Func = "LongShiftLeft";
					else if (Op == Operator.ShiftRight) Func = Type is UnsignedType ? "ULongShiftRight" : "LongShiftRight";

					Node = Expressions.CreateCallIndexExpr(Node.Code, Root,
						Operator.Call, new PString(Func), Ch);

					if (Node == null) return PlugInRes.Failed;
					Node.Type = OpNode.Type;
					return PlugInRes.Ready;
				}
				else
				{
					Data.Index = AdjustRegs(OpNode, true);
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsBitwiseOp(Op))
			{
				Data.Index = AdjustRegs(OpNode, true);
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsArithmeticalOp(Op))
			{
				if (NeedSwap(Ch)) OpNode.Swap();

				var CalcedNew = false;
				if ((Op == Operator.Multiply || Op == Operator.Divide) && Ch[1].Type is NonFltNumType)
				{
					var ConstCh1 = Ch[1] as ConstExpressionNode;
					if (ConstCh1 != null)
					{
						var V = ConstCh1.Unsigned;
						if (Helper.Pow2(V) == V)
						{
							var NewOp = Op == Operator.Multiply ? Operator.ShiftLeft : Operator.ShiftRight;
							var CNode = Root.NewNode(new ConstExpressionNode(Ch[1].Type, Helper.Pow2Sqrt(V), Node.Code));
							Ch = new List<ExpressionNode>() { Ch[0], CNode };
							Node = Root.NewNode(new OpExpressionNode(NewOp, Ch, Node.Code));
							CalcedNew = true;

							if (Node != null)
							{
								Data = Node.ArchData as x86NodeData;
								return PlugInRes.Ready;
							}

							return PlugInRes.Failed;
						}
					}
				}

				if (!CalcedNew)
				{
					var Size = Node.Type.Size;
					if (Op == Operator.Multiply || Op == Operator.Divide || Op == Operator.Modolus)
					{
						if (Size > Arch.RegSize)
						{
							var Func = (string)null;
							if (Op == Operator.Multiply) Func = "LongMul";
							else if (Op == Operator.Divide) Func = Type is UnsignedType ? "ULongDiv" : "LongDiv";
							else if (Op == Operator.Modolus) Func = Type is UnsignedType ? "ULongMod" : "LongMod";

							Node = Expressions.CreateCallIndexExpr(Node.Code, Root,
								Operator.Call, new PString(Func), Ch);

							if (Node == null) return PlugInRes.Failed;
							Node.Type = OpNode.Type;
							return PlugInRes.Ready;
						}
						else
						{
							/* imul 1:
							 *		dst: r16/r32
							 *		src: m16/m32/r16/r32/i16/i32
							 *		
							 * imul 2 / idiv / div:
							 *		dst: accumulator
							 *		src: m8/m16/m32/r8/r16/r32
							 *		
							 * remainder (except imul 1):
							 *		byte: ah
							 *		word: dx
							 *		dword: edx
							 */

							Data.Index = AdjustRegs(OpNode, true);
							if (Op != Operator.Multiply || Size == 1)
							{
								if (Ch[1] is ConstExpressionNode)
								{
									var C = Ch[1] as ConstExpressionNode;
									Ch[1] = Container.GlobalScope.CreateConstRId(C, Root);
									if (Ch[1] == null) return PlugInRes.Failed;
								}

								var Ch0Data = Ch[0].ArchData as x86NodeData;
								var Ch1Data = Ch[1].ArchData as x86NodeData;
								Ch0Data.Input = new x86RegPosition(Arch, Size, 0);

								if (Op != Operator.Multiply)
								{
									if (Ch1Data.CantBe == null)
										Ch1Data.CantBe = new x86RegList(Arch.RegCount);

									if (Size == 1) Ch1Data.CantBe.SetUsed(0, 2);
									else Ch1Data.CantBe.SetUsed(2, Size);
								}

								Data.UsedRegs = new x86RegList(Arch.RegCount);
								Data.Index = -1;
								Data.NewScope = true;

								if (Size == 1)
								{
									Data.UsedRegs.SetUsed(0, 2);

									var Pos = new x86RegPosition(Arch, 1, 0, Op == Operator.Modolus);
									Data.Output = Pos;
								}
								else
								{
									Data.UsedRegs.SetUsed(0, Size);
									Data.UsedRegs.SetUsed(2, Size);

									var RegId = Op == Operator.Modolus ? 2 : 0;
									var Pos = new x86RegPosition(Arch, Size, RegId);
									Data.Output = Pos;
								}
							}
							else
							{
								Data.DataCalcPos = x86DataCalcPos.GeneralReg;
							}
						}
					}
					else
					{
						Data.Index = AdjustRegs(OpNode, true);
					}
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsRelEqualityOp(Op))
			{
				if (NeedSwap(Ch)) OpNode.Swap();
				Data.Index = AdjustRegs(OpNode, false);
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Neg || Op == Operator.Complement)
			{
				if (Type.Size > Arch.RegSize && (Ch[0] is IdExpressionNode || Ch[0] is ConstExpressionNode))
				{
					var Null = Expressions.CreateConstNode(Node.Code,
						new ConstData(0), Ch[0].Type, Root);

					if (Null == null) return PlugInRes.Failed;
					var NCh = new List<ExpressionNode>() { Null, Ch[0] };
					Node = Root.NewNode(new OpExpressionNode(Operator.Subract, NCh, Node.Code));
					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else
				{
					var ChIndex = (Ch[0].ArchData as x86NodeData).Index;
					if (ChIndex == -1)
					{
						Ch[0] = CreateMoveNode(Ch[0], 0);
						if (Ch[0] == null) return PlugInRes.Failed;
						Data.Index = 0;
					}
					else
					{
						Data.Index = ChIndex;
					}
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op != Operator.Assignment)
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewOpNode_Float(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;

			if (Op != Operator.Assignment && !AdjustConstFltNode(Ch))
				return PlugInRes.Failed;

			//--------------------------------------------------------------------------------------
			if (Operators.IsMathsOp(Op))
			{
				var Ch0Data = Ch[0].ArchData as x86NodeData;
				Data.Index = -1;
				Data.FPUItemsOnStack = Ch0Data.FPUItemsOnStack;

				if (Op == Operator.ACos)
				{
					Node = Expressions.CreateCallIndexExpr(Node.Code, Root,
						Operator.Call, new PString("Math_ArcCosine"), Ch);

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else if (Op == Operator.ASin)
				{
					Node = Expressions.CreateCallIndexExpr(Node.Code, Root,
						Operator.Call, new PString("Math_ArcSine"), Ch);

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else if (Op == Operator.ATan2)
				{
					if (!AdjustRegs_Float(OpNode, true))
						return PlugInRes.Failed;
				}
				else if (Op == Operator.Tan)
				{
					Data.UsedFPUStack = 1;
					if (Ch0Data.FPUItemsOnStack >= 8)
					{
						if ((Ch[0] = CreateMoveNode(Ch[0], 0, x86DataCalcPos.Memory)) == null)
							return PlugInRes.Failed;

						Ch[0].Type = Container.GetType(typeof(FloatType), 8);
					}
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Assignment)
			{
				var RId = Ch[0] as IdExpressionNode;
				var Var = RId != null ? RId.Id as LocalVariable : null;
				if (!AdjustRegs_Float(OpNode, false, false)) return PlugInRes.Failed;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsArithmeticalOp(Op))
			{
				if (NeedSwap(Ch)) OpNode.Swap();

				Data.Index = -1;
				if (!AdjustRegs_Float(OpNode, true)) return PlugInRes.Failed;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsRelEqualityOp(Op))
			{
				if (NeedSwap(Ch)) OpNode.Swap();

				Data.Index = -1;
				//Data.NewScope = true;
				if (!AdjustRegs_Float(OpNode, true)) return PlugInRes.Failed;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Neg)
			{
				Data.Index = -1;
			}

			//--------------------------------------------------------------------------------------
			else
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewOpNode_Ptr(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;

			//--------------------------------------------------------------------------------------
			if (Operators.IsArithmeticalOp(Op))
			{
				if (Op == Operator.Add)
				{
					var PType = Ch[0].Type as PointerType;
					Ch[1] = MulBy(Ch[1], PType.Child.Size);
					if (Ch[1] == null) return PlugInRes.Failed;
				}

				Data.Index = AdjustRegs(OpNode, true);
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Index)
			{
				var pType = Ch[0].Type as PointerType;
				var Size = pType.Child.Size;
				for (var i = 1; i < Ch.Count; i++)
				{
					if (Ch[i] is ConstExpressionNode) Ch[i] = MulBy(Ch[i], Size);
					else (Ch[i].ArchData as x86NodeData).MulBy = Size;
				}

				Data.Index = -1;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsRelEqualityOp(Op))
			{
				if (NeedSwap(Ch)) OpNode.Swap();
				Data.Index = AdjustRegs(OpNode, false);
			}

			//--------------------------------------------------------------------------------------
			else if (Op != Operator.Assignment)
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewOpNode_Bool(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;
			
			//--------------------------------------------------------------------------------------
			if (Operators.IsBoolRetOp(Op))
			{
				var Log = !Operators.IsRelEqualityOp(Op);
				if (!Log && Ch[0] is ConstExpressionNode && !(Ch[1] is ConstExpressionNode))
					OpNode.Swap();

				if (Operators.IsRelEqualityOp(Op))
				{
					for (var i = 0; i < Ch.Count; i++)
					{
						var OpCh = Ch[i] as OpExpressionNode;
						if (OpCh != null && Operators.IsBoolRetOp(OpCh.Operator))
						{
							Ch[i] = CreateMoveNode(Ch[i], 0);
							if (Ch[i] == null) return PlugInRes.Failed;
						}
					}
				}

				Data.Index = AdjustRegs(OpNode, false);
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Not)
			{
				var False = Root.NewNode(Expressions.GetBoolValue(Container, false, Node.Code));
				var nCh = new List<ExpressionNode>() { Ch[0], False };
				Node = Root.NewNode(new OpExpressionNode(Operator.Equal, nCh, Node.Code));
			}

			//--------------------------------------------------------------------------------------
			else if (Op != Operator.Assignment)
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		bool[] TupleAssignment_AlwaysLink = new bool[] { false, true };
		public PlugInRes NewOpNode_Structured(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;

			//--------------------------------------------------------------------------------------
			if (Op == Operator.Neg || Op == Operator.Complement || Operators.IsBitArithmOp(Op))
			{
				if (OpNode.Type is TupleType)
				{
					var Code = Node.Code;
					Node = Expressions.ExtractTupleOp(Node, Root, (i, Args) =>
                    {
                        return Root.NewNode(new OpExpressionNode(Op, Args, Code));
                    });

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else
				{
					throw new Exception("ERROR");
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Member)
			{
				if (Ch[0] is OpExpressionNode)
				{
					var OpCh = Ch[0] as OpExpressionNode;
					var OpChOp = OpCh.Operator;

					if (OpChOp == Operator.New || OpChOp == Operator.Call)
					{
						Ch[0] = CreateMoveNode(Ch[0], 0, x86DataCalcPos.Memory);
						if (Ch[0] == null) return PlugInRes.Failed;
					}
				}

				Data.Index = -1;
			}

            //--------------------------------------------------------------------------------------
            else if (Op == Operator.Assignment)
            {
                var OpCh0 = Ch[0] as OpExpressionNode;
                if (OpCh0 != null && OpCh0.Operator == Operator.CreateTuple)
                {
					var Code = Node.Code;
					Node = Expressions.ExtractTupleOp(Node, Root, (i, Args) =>
                    {
                        return Root.NewNode(new OpExpressionNode(Operator.Assignment, Args, Code));
					}, TupleAssignment_AlwaysLink);

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
                }
            }

            //--------------------------------------------------------------------------------------
            else
            {
                throw new Exception("ERROR");
            }

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewOpNode_Type(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Op = OpNode.Operator;
			var Ch = OpNode.Children;
			var Type = Ch[0].Type.RealType;

			if (Type is NonFltNumType) return NewOpNode_NonFloat(ref Node);
			else if (Type is FloatType) return NewOpNode_Float(ref Node);
			else if (Type is BoolType) return NewOpNode_Bool(ref Node);
			else if (Type is PointerType) return NewOpNode_Ptr(ref Node);
			else if (Type is StructuredType) return NewOpNode_Structured(ref Node);
			else throw new Exception("ERROR");
		}

        public ExpressionNode NewCallOpNode(ExpressionNode Node)
        {
            var OpNode = Node as OpExpressionNode;
            var Ch = OpNode.Children;
            var Data = Node.ArchData as x86NodeData;

            var FuncType = Ch[0].Type as FunctionType;
            Data.Index = -1;
            Data.UsedRegs = new x86RegList(Arch.RegCount);
            Data.UsedFPUStack = int.MaxValue;

            //--------------------------------------------------------------------------------------
            for (var i = 1; i < Ch.Count; i++)
            {
                var ChData = Ch[i].ArchData as x86NodeData;
                ChData.NewScope = true;

                if (Ch[i] is ConstExpressionNode & Ch[i].Type is FloatType)
                {
                    Ch[i] = AdjustConstFltNode(Ch[i] as ConstExpressionNode);
                    if (Ch[i] == null) return null;
                }
            }

            for (var i = 0; i < Arch.RegCount; i++)
                if (x86Architecture.IsVolatileReg(i, FuncType.Conv))
                    Data.UsedRegs.SetUsed(i, Arch.RegSize);

            //--------------------------------------------------------------------------------------
            var RetType = FuncType.RetType;
            if (!(RetType is RefType)) RetType = RetType.RealType;
            var S = RetType.Size;

            var NeedMoveRetType = false;
            if (RetType is FloatType)
            {
                Data.FPUItemsOnStack = 1;
            }
            else if (RetType is PointerType || RetType is BoolType || RetType is FunctionType ||
                RetType is RefType || RetType is ClassType)
            {
                var Pos = new x86RegPosition(Arch, S, 0);
				Data.Output = Pos;
            }
            else if (RetType is NonFltNumType)
            {
                x86DataPosition Pos = null;
                if (S == Arch.RegSize) Pos = new x86RegPosition(Arch, S, 0);
				else if (S == Arch.RegSize * 2) Pos = Arch.MultiRegPos(0, 2);
				Data.Output = Pos;
            }
            else if (!(RetType is VoidType))
            {
                NeedMoveRetType = true;
            }

            //--------------------------------------------------------------------------------------
            if (FuncType.Conv == CallConv.AsCall)
            {
                var Index = NeedMoveRetType ? 1 : 0;
                var OpCh0 = Ch[0] as OpExpressionNode;
                if (OpCh0 != null && OpCh0.Operator == Operator.Member)
                    Index++;

				if (Index > 0)
				{
					Data.PreAllocate = new x86RegList(Arch.RegCount);
					for (var i = 0; i < Index; i++)
					{
						var Reg = x86DataAllocator.RegAllocSequence[i];
						Data.PreAllocate.SetUsed(Reg, Arch.RegSize);
					}
				}

                var Types = new Type[Ch.Count - 1];
                for (var i = 1; i < Ch.Count; i++)
                    Types[i - 1] = Ch[i].Type;

                foreach (var i in Arch.EnumFirstAsCallParams(Types, Index))
                {
                    var ChNode = Ch[i + 1];
                    if (ChNode is OpExpressionNode || ChNode is CastExpressionNode)
                    {
                        var P = Arch.GetArgP(ref Index, ChNode.Type.Size);
                        ChNode = CreateLinkingNode(ChNode, Node, P);
                        if (ChNode == null) return null;
                        Ch[i + 1] = ChNode;
                    }
                }
            }

            return Node;
        }

		public PlugInRes NewOpNode(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Data = Node.ArchData as x86NodeData;

			if (Op == Operator.New)
			{
				Data.Index = -1;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Condition)
			{
				var ChData = Ch[1].ArchData as x86NodeData;
				var RegId = ChData.Index == -1 ? 0 : ChData.Index;

				for (var i = 1; i < 3; i++)
				{
					var n = Ch[i];
					ChData = n.ArchData as x86NodeData;

					if (ChData.Index != RegId)
					{
                        n = CreateMoveNode(n, RegId, x86Architecture.TypePos(Ch[i].Type));
						Ch[i] = n;
					}
				}

				var Ch0Data = Ch[0].ArchData as x86NodeData;
				Ch0Data.NewScope = true;
				Data.Index = RegId;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Call)
			{
                Node = NewCallOpNode(Node);
				if (Node == null) return PlugInRes.Failed;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Assignment)
			{
				Data.NewScope = true;
				Data.Index = -1;
				var Res = NewOpNode_Type(ref Node);
				if (Res == PlugInRes.Ready || Res == PlugInRes.Failed)
					return Res;
			}

			//--------------------------------------------------------------------------------------
            else if (Op == Operator.Address)
			{
				Data.Index = 0;
            }

            //--------------------------------------------------------------------------------------
            else if (Op == Operator.CreateTuple)
            {
                Data.Index = 0;
                Data.DataCalcPos = x86DataCalcPos.Memory;
            }

            //--------------------------------------------------------------------------------------
            else
			{
				var Res = NewOpNode_Type(ref Node);
				if (Res == PlugInRes.Ready || Res == PlugInRes.Failed)
					return Res;
            }

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewCastNode_NonFloat(ref ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			var Ch = CastNode.Child;
			var Data = Node.ArchData as x86NodeData;

			var ChData = Ch.ArchData as x86NodeData;
			Data.Index = ChData.Index == -1 ? 0 : ChData.Index;

            var From = Ch.Type.RealType;
            var To = Node.Type.RealType;
            var ToSize = To.Size;

			//--------------------------------------------------------------------------------------
			if (From is FloatType)
			{
                if (ToSize > Arch.RegSize && To is UnsignedType)
				{
                    if (ToSize != 8) throw new NotImplementedException();
					var Func = Ch.Type.Size == 4 ? "FloatToULong" : "DoubleToULong";

					Node = Expressions.CreateCallIndexExpr(Node.Code, Root, Operator.Call,
						new PString(Func), Ch);

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
                else if (ToSize == 1 || To is UnsignedType)
				{
					CastNode.ArchData = Data;
                    CastNode.Type = Container.GetType(To.GetType(), ToSize * 2);
                    Node = CreateSizeChangerNode(CastNode, ToSize, x86DataCalcPos.Memory);
				}
			}

			//--------------------------------------------------------------------------------------
			else if (From is NonFltNumType)
			{
                if (From.Size == ToSize)
				{
					Node = Ch;
					Node.Type = CastNode.Type;
				}
                else if (From is SignedType && ToSize > Arch.RegSize && Ch.Type.Size < ToSize)
				{
					Data.Output = Arch.MultiRegPos(0, 2);
					Data.UsedRegs = new x86RegList(Arch.RegCount);
					Data.UsedRegs.SetUsed(0, Arch.RegSize);
					Data.UsedRegs.SetUsed(2, Arch.RegSize);
					Data.Index = -1;
					Data.NewScope = true;
				}
			}

			//--------------------------------------------------------------------------------------
			else
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewCastNode_Float(ref ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			var Ch = CastNode.Child;
			var Data = Node.ArchData as x86NodeData;
			Data.Index = -1;

            var From = Ch.Type.RealType;
            var To = Node.Type.RealType;

			//--------------------------------------------------------------------------------------
            if (From is FloatType)
			{
				Node = Ch;
				Node.Type = CastNode.Type;
			}

			//--------------------------------------------------------------------------------------
            else if (From is NonFltNumType)
			{
                var Size = From.Size;

                if (From is UnsignedType && Size > Arch.RegSize)
				{
					if (Size != 8) throw new Exception("ERROR");
					Node = Expressions.CreateCallIndexExpr(Node.Code, Root, Operator.Call,
						new PString("ULongToFloat"), Ch);

					if (Node == null) return PlugInRes.Failed;
					else return PlugInRes.Ready;
				}
				else
				{
					var Ok = true;
                    if (From is UnsignedType) Ok = false;
					else if (Size == 1) Ok = false;

					if (!Ok)
					{
						Ch = CreateSizeChangerNode(Ch, Size * 2);
						(Ch.ArchData as x86NodeData).DataCalcPos = x86DataCalcPos.Memory;
					}
					/*else
					{
						if (Ch is IdExpressionNode)
						{
							var IdCh = Ch as IdExpressionNode;
							IdCh.Id.CanBeInReg = false;
						}
						else
						{
							var ChData = Ch.Data as x86NodeData;
							if (ChData.Index != -1) ChData.DataCalcPos = x86DataCalcPos.Memory;
						}
					}*/

					Data.FPUItemsOnStack = 1;
					CastNode.Child = Ch;
				}
			}

			//--------------------------------------------------------------------------------------
			else
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewCastNode_Ptr(ref ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			var Ch = CastNode.Child;
			var Data = Node.ArchData as x86NodeData;

			var ChData = Ch.ArchData as x86NodeData;
			Data.Index = ChData.Index == -1 ? 0 : ChData.Index;

            var From = Ch.Type.RealType;
            var To = Node.Type.RealType;

			//--------------------------------------------------------------------------------------
			if (From is PointerType)
			{
				if (Ch.Type.Size != Node.Type.Size)
					throw new Exception("ERROR");
			}

			//--------------------------------------------------------------------------------------
			else
			{
				throw new Exception("ERROR");
			}

			return PlugInRes.Succeeded;
		}

		public PlugInRes NewCastNode_Structured(ref ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			var Ch = CastNode.Child;
			var Data = Node.ArchData as x86NodeData;

            var ChData = Ch.ArchData as x86NodeData;
            Data.Index = ChData.Index == -1 ? 0 : ChData.Index;
            Data.DataCalcPos = x86DataCalcPos.Memory;

            var From = Ch.Type.RealType;
            var To = Node.Type.RealType;
			if (From.IsEqual(To)) return PlugInRes.Succeeded;

            if (To is TupleType && From is TupleType)
			{
                var DstType = To as TupleType;
				var Code = Node.Code;

                Node = Expressions.ExtractTupleOp(Node, Root, (i, Nodes) =>
                {
                    var MemVar = DstType.Members[i] as MemberVariable;
                    var Ret = Root.NewNode(new CastExpressionNode(MemVar.Type, Nodes[0], Code));
					if (Ret == null) return null;

					Ret.IncRegs(i + 1);
					return Ret;
                });

				if (Node == null) return PlugInRes.Failed;
				else return PlugInRes.Ready;
			}
			else
			{
				throw new Exception("ERROR");
			}
		}

		public PlugInRes NewCastNode(ref ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			var Ch = CastNode.Child;
			var Data = Node.ArchData as x86NodeData;
            var RealType = Node.Type.RealType;

			if (Ch.Type.RealType is AutomaticType)
			{
				Ch.Type = CastNode.Type;
				Node = Ch;
				return PlugInRes.Succeeded;
			}
            else if (RealType is NonFltNumType) return NewCastNode_NonFloat(ref Node);
            else if (RealType is FloatType) return NewCastNode_Float(ref Node);
            else if (RealType is PointerType) return NewCastNode_Ptr(ref Node);
            else if (RealType is StructuredType) return NewCastNode_Structured(ref Node);
			else throw new Exception("ERROR");
		}

		public override PlugInRes NewNode(ref ExpressionNode Node)
		{
			var Data = Node.ArchData as x86NodeData;
			if (Data != null) throw new Exception("ERROR");
			Data = new x86NodeData();
			Node.ArchData = Data;

			if (Node.LinkedNodes != null)
			{
				foreach (var e in Node.LinkedNodes)
					e.ArchData = new x86LinkedNodeData(null);
			}

			// ------------------------------------------------------------------------------------
			if (Node is LinkingNode)
			{
				Data.Index = -1;
			}

			else if (Node is MacroExpressionNode)
			{
				return PlugInRes.Succeeded;
			}

			else if (Node is StrExpressionNode)
			{
				return PlugInRes.Succeeded;
			}

			else if (Node is IdExpressionNode)
			{
				var RIdNode = Node as IdExpressionNode;
				var Id = RIdNode.Id;
				Data.Index = -1;

				if (Id is Variable)
				{
					var T = RIdNode.Type;
					if (T is FloatType || T is ValueType)
						Id.CanBeInReg = false;
				}
			}

			else if (Node is OpExpressionNode)
			{
				var Res = NewOpNode(ref Node);
				if (Res == PlugInRes.Ready || Res == PlugInRes.Failed)
					return Res;
			}

			else if (Node is CastExpressionNode)
			{
				var Res = NewCastNode(ref Node);
				if (Res == PlugInRes.Ready || Res == PlugInRes.Failed)
					return Res;
			}

			else if (Node is ConstExpressionNode)
			{
				var ConstNode = Node as ConstExpressionNode;
				Data.Index = -1;
			}

			// ------------------------------------------------------------------------------------
			Data = Node.ArchData as x86NodeData;
			if (Node == null || Node.Type == null || Data == null || Data.Index == int.MaxValue)
				throw new Exception("ERROR");

			if (!PostProcNode(Node)) return PlugInRes.Failed;
			else return PlugInRes.Succeeded;
		}

		public bool PostProcNode(ExpressionNode Node)
		{
            if (!CalcLinkedNodes(Node)) return false;
            if (!CalcNodeCantBe(Node)) return false;
			return true;
		}

        public bool CalcLinkedNodes(ExpressionNode Node)
        {
            if (Node.LinkedNodes != null)
                foreach (var e in Node.LinkedNodes)
                {
                    var ChData = e.Node.ArchData as x86NodeData;
                    ChData.NewScope = true;
                }

            return true;
		}

        bool CalcNodeCantBe(ExpressionNode Node)
		{
			var Data = Node.ArchData as x86NodeData;
            if (Data.UsedFPUStack < Data.FPUItemsOnStack)
                Data.UsedFPUStack = Data.FPUItemsOnStack;

            foreach (var Ch in Node.EnumChildren)
            {
                var ChData = Ch.ArchData as x86NodeData;
                if (ChData.UsedFPUStack > Data.UsedFPUStack)
                    Data.UsedFPUStack = ChData.UsedFPUStack;
            }

            // ----------------------------------------------------------------
			var UsedRegs = (x86RegList)null;
			foreach (var Ch in Node.EnumChWithoutLinkedNodes)
			{
				var ChUsed = (Ch.ArchData as x86NodeData).UsedRegs;
				if (ChUsed == null) continue;

				if (UsedRegs == null) UsedRegs = ChUsed.Copy();
				else UsedRegs.SetUsed(ChUsed);
			}

			// ----------------------------------------------------------------
			if (Node.LinkedNodes != null)
			{
				for (var i = Node.LinkedNodes.Count - 1; i >= 0; i--)
				{
					var e = Node.LinkedNodes[i];
					var LNode = e.Node;
					var LData = LNode.ArchData as x86NodeData;

					if (UsedRegs != null)
					{
						if (LData.CantBe != null) LData.CantBe.SetUsed(UsedRegs);
						else LData.CantBe = UsedRegs.Copy();

						if (LData.UsedRegs != null) UsedRegs.SetUsed(LData.UsedRegs);
					}
					else
					{
						if (LData.UsedRegs != null) UsedRegs = LData.UsedRegs.Copy();
					}
				}
			}

            // ----------------------------------------------------------------
            if (UsedRegs != null)
            {
                if (Data.UsedRegs == null) Data.UsedRegs = UsedRegs;
                else Data.UsedRegs.SetUsed(UsedRegs);
            }

			// ----------------------------------------------------------------
			if (Node is OpExpressionNode)
			{
				var OpNode = Node as OpExpressionNode;
				var Op = OpNode.Operator;
				var Ch = OpNode.Children;

				if (Operators.IsBoolRetBitArithmOp(Op))
				{
					var Dst = Ch[0];
					var Src = Ch[1];

					var DstData = Dst.ArchData as x86NodeData;
					var SrArchData = Src.ArchData as x86NodeData;

					if (!OpNode.Reverse)
					{
						if (SrArchData.UsedRegs != null)
						{
							var Regs = SrArchData.UsedRegs;

							if (DstData.CantBe == null)
								DstData.CantBe = Regs.Copy();
							else DstData.CantBe.SetUsed(Regs);
						}
					}
					else
					{
						if (DstData.Output != null)
						{
							var Regs = DstData.Output.GetRegs();

							if (SrArchData.CantBe == null)
								SrArchData.CantBe = Regs.Copy();
							else SrArchData.CantBe.SetUsed(Regs);
						}
					}
				}
			}

            return true;
		}

		private CastExpressionNode CreateSizeChangerNode(ExpressionNode Ch, int NewSize,
			x86DataCalcPos DataCalcPos = x86DataCalcPos.GRegMem)
		{
			var NewType = Container.GetType(Ch.Type.GetType(), NewSize);
			var nNode = new CastExpressionNode(NewType, Ch, Ch.Code);
			var Data = new x86NodeData();
			nNode.ArchData = Data;
			Data.DataCalcPos = DataCalcPos;

			var ChData = Ch.ArchData as x86NodeData;
			Data.Index = ChData.Index == -1 ? 0 : ChData.Index;
            if (!PostProcNode(nNode)) return null;
			return nNode;
		}

		private ExpressionNode CreateMoveNode(ExpressionNode n, int RegId,
			x86DataCalcPos DataCalcPos = x86DataCalcPos.GRegMem, bool ModCastNode = true)
		{
			if (n is CastExpressionNode && ModCastNode)
			{
				var Data = n.ArchData as x86NodeData;
				Data.Index = RegId;
				Data.DataCalcPos &= DataCalcPos;
			}
			else
			{
				n = new CastExpressionNode(n.Type, n, n.Code);
				var Data = new x86NodeData();
				n.ArchData = Data;
				Data.Index = RegId;
				Data.DataCalcPos = DataCalcPos;
                if (!PostProcNode(n)) return null;
			}

			return n;
		}

		bool NeedLoadRId(ExpressionNode Node)
		{
			var RId = Node as IdExpressionNode;
			if (RId == null) return false;

			var Type = RId.Type;
			if (!(Type is FloatType))
				throw new Exception("ERROR");

			var S = Type.Size;
			return S != 4 && S != 8;
		}

		ExpressionNode AdjustConstFltNode(ConstExpressionNode Node)
		{
			if (Node is ConstExpressionNode && Node.Type is FloatType)
			{
				var Val = Node.Double;
				if (Val != 0.0 && Val != 1.0 && Val != Math.PI)
					return Container.GlobalScope.CreateConstRId(Node, Root);
				else return CreateMoveNode(Node, -1);
			}

			return Node;
		}

		bool AdjustConstFltNode(List<ExpressionNode> Ch)
		{
			for (var i = 0; i < Ch.Count; i++)
			{
				var N = Ch[i].RealNode;
				if (N is ConstExpressionNode && N.Type is FloatType)
				{
					N = AdjustConstFltNode(N as ConstExpressionNode);
					if (N == null) return false;
					Ch[i] = N;
				}
			}

			return true;
		}

		bool AdjustRegs_Float(OpExpressionNode Node, bool Mod, bool RemoveIntCasts = true)
		{
			var Ch = Node.Children;
			var Data = Node.ArchData as x86NodeData;

			var RCh0 = Ch[0].RealNode;
			var RCh1 = Ch[1].RealNode;

			var Ch0Data = Ch[0].ArchData as x86NodeData;
			var Ch1Data = Ch[1].ArchData as x86NodeData;

			// -----------------------------------------------------------------------
            if (x86Architecture.NeedLoadFloatDst(Ch[0], Mod))
			{
				RCh0 = CreateMoveNode(Ch[0], -1);
				Ch0Data = RCh0.ArchData as x86NodeData;
				Ch0Data.FPUItemsOnStack = 1;
				Ch[0] = RCh0;
			}

			if (NeedLoadRId(RCh1))
			{
				RCh1 = CreateMoveNode(Ch[1], -1);
				Ch1Data = RCh1.ArchData as x86NodeData;
				Ch1Data.FPUItemsOnStack = 1;
				Ch[1] = RCh1;
			}

			if (RemoveIntCasts)
			{
				RCh1 = FloatOpIntSrc(Ch[1]);
				if (RCh1 == null) return false;
				Ch[1] = RCh1;
			}

			// -----------------------------------------------------------------------
			if (Ch1Data.UsedFPUStack >= 8 && Mod)
			{
				if ((Ch[0] = CreateMoveNode(Ch[0], 0, x86DataCalcPos.Memory)) == null)
					return false;

				Ch[0].Type = Container.GetType(typeof(FloatType), 8);
				Ch0Data = Ch[0].ArchData as x86NodeData;
				Ch[1].IncRegs();
			}

			Data.FPUItemsOnStack = Ch0Data.FPUItemsOnStack + Ch1Data.FPUItemsOnStack;
			return true;
		}
		
		int AdjustRegs(OpExpressionNode Node, bool Mod)
		{
			var Ch = Node.Children;
			var DstIndex = Node.Reverse ? 1 : 0;

			var Dst = Ch[DstIndex];
			var Src = Ch[1 - DstIndex];

			var DstData = Dst.ArchData as x86NodeData;
			var SrArchData = Src.ArchData as x86NodeData;

			var NeedMove = (DstData.Index != 0 && Mod) || Dst is ConstExpressionNode;
			if (!NeedMove && Dst.SamePosition(Src, false)) NeedMove = true;

			if (NeedMove)
			{
				Ch[DstIndex] = Dst = CreateMoveNode(Ch[DstIndex], 0);
				DstData = Dst.ArchData as x86NodeData;
			}

			if (SrArchData != null && SrArchData.Index != -1 && SrArchData.Index == DstData.Index)
				Src.IncRegs();

			return Mod ? 0 : -1;
		}
		
		private static bool NeedSwap(List<ExpressionNode> Ch)
		{
			if (Ch[0].Type is FloatType)
				return Ch[1] is OpExpressionNode && !(Ch[0] is OpExpressionNode);

			var A = Ch[0].RealNode;
			var B = Ch[1].RealNode;

			var AIndex = (A.ArchData as x86NodeData).Index;
			var BIndex = (B.ArchData as x86NodeData).Index;

			return AIndex == -1 && BIndex != -1;
		}

		private ExpressionNode FloatOpIntSrc(ExpressionNode Node)
		{
			var CastNode = Node as CastExpressionNode;
			if (CastNode == null) return Node;

			var Size = CastNode.Child.Type.Size;
			if (Size != 2 && Size != 4) return Node;
			return CastNode.Child;
		}

		private ExpressionNode MulBy(ExpressionNode N, long Num)
		{
			var Four = Root.NewNode(new ConstExpressionNode(N.Type, Num, N.Code));
			var NCh = new List<ExpressionNode>() { N, Four };
			return Root.NewNode(new OpExpressionNode(Operator.Multiply, NCh, N.Code));
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Hungary Hungary
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions