Click here to Skip to main content
15,886,362 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 377.4K   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 enum GetNodePosMode
	{
		Default,
		StrOnly,
		RetNull,
	}

	public class x86Compiler : Compiler
	{
		public x86Architecture Arch;

		public x86Compiler(x86Architecture Arch, CompilerState State)
			: base(State)
		{
			this.Arch = Arch;
		}

		public override string JumpStr(string Label)
		{
			return "\tjmp " + Label + "\n";
		}

		public override string LabelStr(string Label)
		{
			return Label + ":\n";
		}

		public override void DeclareUnknownBytes(int Bytes)
		{
			var Size = 8;
			while (Size > 0)
			{
				if (Bytes >= Size)
				{
					var Ins = "\t" + x86Architecture.GetDataTypeString(Size) + " ?";
					var Count = Bytes / Size;
					for (var i = 1; i < Count; i++)
						Ins += ", ?";

					Bytes = Bytes % Size;
					Append(Ins + "\n");
				}

				Size /= 2;
			}
		}

		public unsafe override void Declare(Type Type, ConstData Data)
		{
			var TypeStr = x86Architecture.GetDataTypeString(Type.Size);
			if (Data == null)
			{
				Append("\t" + TypeStr + " ?\n");
				return;
			}

			var DefStr = Data.GetDefString();
			if (Type is FloatType && Type.Size == 4)
			{
				var FloatData = (float)Data.DoubleData;
				DefStr = (*(uint*)(&FloatData)).ToString();
			}

			Append("\t" + TypeStr + " " + DefStr + "\n");
		}

		public override void DeclareLabelPtr(string Label)
		{
			var TypeStr = x86Architecture.GetDataTypeString(Arch.RegSize);
			Append("\t" + TypeStr + " " + Label + "\n");
		}

		public override void DeclareLabelPtr(int Label)
		{
			var TypeStr = x86Architecture.GetDataTypeString(Arch.RegSize);
			Append("\t" + TypeStr + " _" + Label + "\n");
		}

		void MoveData(x86MoveCondBranch Branch, string Cond = null)
		{
			MoveData(Branch.Dst, Branch.Src, Branch.Scope, Branch.SrcSigned, Cond);
		}

		public override void GetConditionCode(ExpressionNode Condition, CondBranch Then,
			CondBranch Else, bool ThenAllPathJumpAway = false, bool LinkedNodesCalced = false,
			int NextLabel = -1)
        {
			var Data = Condition.ArchData as x86NodeData;
			var OpNode = Condition as OpExpressionNode;
			if (OpNode == null) throw new Exception("ERROR");
			var Op = OpNode.Operator;
			var Ch = OpNode.Children;

			if (!LinkedNodesCalced) CalcLinkedNodes(Condition);

			if (ConditionalMove(Then, Else, Data, Op, Ch)) return;
			if (JumpCondition(OpNode, Then, Else)) return;
			StdCondition(OpNode, Then, Else, ThenAllPathJumpAway, NextLabel);
        }

		private bool JumpCondition(OpExpressionNode OpNode, CondBranch Then, CondBranch Else)
		{
			var JumpThen = Then as JumpCodeBranch;
			var JumpElse = Else as JumpCodeBranch;
			if (JumpThen == null && JumpElse == null) return false;

			var ThenLbl = JumpThen == null ? State.NextLabelIndex : JumpThen.Label;
			var ElseLbl = JumpElse == null ? State.NextLabelIndex : JumpElse.Label;
			
			var Op = OpNode.Operator;
			var Last = Op == Operator.Or;
			if (JumpThen != null) Last = !Last;

			CalcCondAsmCode(OpNode, ThenLbl, ElseLbl, Operator.Nothing, Last, true);

			if (JumpThen == null)
			{
				Label(ThenLbl);
				GetBranchCode(Then);
			}
			else if (JumpElse == null)
			{
				Label(ElseLbl);
				GetBranchCode(Else);
			}
			else
			{
				GetBranchCode(Else);
			}

			return true;
		}

		private void StdCondition(OpExpressionNode OpNode, CondBranch Then, CondBranch Else,
			bool ThenAllPathJumpAway, int NextLabel)
		{
			var Op = OpNode.Operator;
			var ThenLabel = State.NextLabelIndex;
			var ElseLabel = State.NextLabelIndex;

			var NextLblCreated = false;
			if (NextLabel == -1)
			{
				NextLabel = State.NextLabelIndex;
				NextLblCreated = true;
			}

			CalcCondAsmCode(OpNode, ThenLabel, ElseLabel, Operator.Nothing,
				Op == Operator.Or, true);

			GetLblsCode(OpNode, ThenLabel, ElseLabel,
				NextLabel, Then, Else, ThenAllPathJumpAway);

			if (NextLblCreated) Label(NextLabel);
		}

		private bool ConditionalMove(CondBranch Then, CondBranch Else, x86NodeData Data, Operator Op, List<ExpressionNode> Ch)
		{
			if (Operators.IsRelEqualityOp(Op) && Then is x86MoveCondBranch &&
				(Else == null || Else is x86MoveCondBranch))
			{
				var ThenB = Then as x86MoveCondBranch;
				var ElseB = Else as x86MoveCondBranch;

#if DEBUG
				if (ThenB.Src.Size != ThenB.Dst.Size || ElseB.Src.Size != ElseB.Dst.Size)
					throw new Exception("ERROR");
#endif

				if (ElseB == null || ThenB.Dst.IsEqual(ElseB.Dst))
				{
					if (ThenB.Src.IsEqual(ThenB.Dst))
					{
						Op = Operators.NegateOp(Op);
						var Str = GetCmpCode(Ch, Data.Scope.TmpReg, Op);
						MoveData(ElseB, Str);
					}
					else
					{
						var Str = GetCmpCode(Ch, Data.Scope.TmpReg, Op);
						if (Else != null) MoveData(ElseB);
						MoveData(ThenB, Str);
					}

					return true;
				}
			}

			return false;
		}

		void GetBranchCode(CondBranch Branch)
		{
			if (Branch is CodeCondBranch)
			{
				var CodeB = Branch as CodeCondBranch;
				CodeB.GetCode(this);
			}
			else if (Branch is JumpCodeBranch)
			{
				var JumpB = Branch as JumpCodeBranch;
				Jump(JumpB.Label);
			}
			else if (Branch is x86MoveCondBranch)
			{
				MoveData(Branch as x86MoveCondBranch);
			}
		}

		void GetLblsCode(ExpressionNode Condition, int ThenLabel, int ElseLabel,
			int NextLabel, CondBranch Then, CondBranch Else, bool ThenAllPathJumpAway)
		{
			if (Then != null)
			{
				Label(ThenLabel);
				GetBranchCode(Then);
			}

			if (Else != null)
			{
				var ElseCompiler = Arch.CreateCompiler(State, Container) as x86Compiler;
				ElseCompiler.GetBranchCode(Else);

				if (ElseCompiler.Instructions.Count > 0)
				{
					if (!ThenAllPathJumpAway) Jump(NextLabel);
					Label(ElseLabel);
					Append(ElseCompiler);
					return;
				}
			}

			Label(ElseLabel);
        }

		private string GetCmpCode(x86DataPosition Dst, x86DataPosition Src, x86DataPosition TmpReg, 
			Operator Instruction, Type DstType, Type SrcType)
		{
			string StrInstruction;
			if (DstType is FloatType)
			{
				FloatOp("comp", Src, SrcType is FloatType, false);
				Append("\tfnstsw ax\n");
				Append("\tsahf\n");
				StrInstruction = x86Architecture.OpInstruction(Instruction, false);
			}
			else
			{
				StrInstruction = x86Architecture.OpInstruction(Instruction, DstType is SignedType);
				StdMem2MemOp("\tcmp ", Dst, Src, TmpReg);
			}

			return StrInstruction;
		}

		private string GetCmpCode(List<ExpressionNode> Ch, x86DataPosition TmpReg, Operator Instruction)
		{
			var Type = Ch[0].Type;
			if (Type is FloatType)
			{
				GetNodePos_Float(Ch[0], LoadIds: true);
				return GetCmpCode(null, GetNodePos_Float(Ch[1]),
					TmpReg, Instruction, Type, Ch[1].Type);
			}
			else
			{
				var Dst = GetNodePos(Ch[0]);
				var Src = GetNodePos(Ch[1]);
				return GetCmpCode(Dst, Src, TmpReg,
					Instruction, Type, Ch[1].Type);
			}
		}

		public override void CalcCondAsmCode(ExpressionNode Node, int Then, int Else,
			Operator PrewOp, bool Last, bool LinkedNodesCalced = false)
		{
			if (!LinkedNodesCalced) CalcLinkedNodes(Node);

            var OpNode = Node as OpExpressionNode;
			if (OpNode == null || !Operators.IsBoolRetOp(OpNode.Operator))
			{
				var True = new ConstExpressionNode(Node.Type, true, null);
				var NCh = new List<ExpressionNode>() { Node, True };
				OpNode = new OpExpressionNode(Operator.Equal, NCh, null);
			}

            var Op = OpNode.Operator;
            var Ch = OpNode.Children;
			var Data = Node.ArchData as x86NodeData;

			if (!Operators.IsLogicalOp(Op))
            {
                var Lbl = -1;
                var Ins = Operator.Nothing;

				if (PrewOp == Operator.And || PrewOp == Operator.Nothing)
				{
					Lbl = Last ? Then : Else;
					Ins = Last ? Op : Operators.NegateOp(Op);
				}
				else if (PrewOp == Operator.Or)
				{
					Lbl = Last ? Else : Then;
					Ins = Last ? Operators.NegateOp(Op) : Op;
				}
				else
				{
					throw new Exception("ERROR");
				}

				/*
				var Lbl = Last ? Else : Then;
				var Ins = Last ? Expressions.NegateOp(Op) : Op;
				*/

				var InsStr = (string)null;
				var Type = Ch[0].Type;
				var NextCond = State.NextLabelIndex;
				var TmpReg = Data.Scope.TmpReg;

				if (Type.Size > Arch.RegSize && Type is NonFltNumType)
				{
					var Dst = GetSplPositions(GetNodePos(Ch[0]), Arch.RegSize);
					var Src = GetSplPositions(GetNodePos(Ch[1]), Arch.RegSize);
					var Len = Dst.Length;
					if (Len != Src.Length) throw new Exception("ERROR");

					for (var i = 0; i < Len - 1; i++)
					{
						InsStr = GetCmpCode(Dst[i], Src[i], TmpReg, Ins, Type, Ch[1].Type);
						if (Ins == Operator.Equal || Ins == Operator.Nonequal)
						{
							Append(new x86ConditionalJump(Lbl, InsStr));
						}
						else
						{
							var Signed = i == 0 && Type is SignedType;
							var Greater = x86Architecture.OpInstruction(Operator.Greater, Signed);
							var Less = x86Architecture.OpInstruction(Operator.Less, Signed);

							if (Ins == Operator.Less || Ins == Operator.LessEqual)
							{
								Append(new x86ConditionalJump(NextCond, Greater));
								Append(new x86ConditionalJump(Lbl, Less));
							}
							else if (Ins == Operator.Greater || Ins == Operator.GreaterEqual)
							{
								Append(new x86ConditionalJump(Lbl, Greater));
								Append(new x86ConditionalJump(NextCond, Less));
							}
							else
							{
								throw new Exception("ERROR");
							}
							
						}
					}

					InsStr = GetCmpCode(Dst[Len - 1], Src[Len - 1], TmpReg, Ins, Type, Ch[1].Type);
				}
				else
				{
					InsStr = GetCmpCode(Ch, TmpReg, Ins);
				}

				Append(new x86ConditionalJump(Lbl, InsStr));
				Label(NextCond);
            }
            else
            {
                var Ch0 = Ch[0] as OpExpressionNode;
                var Ch1 = Ch[1] as OpExpressionNode;

				var NewLabel = State.NextLabelIndex;
				var nLast0 = Ch0 != null && Ch0.Operator != Op && Operators.IsLogicalOp(Ch0.Operator);
				var nLast1 = Last || (Ch1 != null && Ch1.Operator != Op && Operators.IsLogicalOp(Ch1.Operator));

                if (Op == Operator.And) CalcCondAsmCode(Ch[0], NewLabel, Else, Op, nLast0);
                else if (Op == Operator.Or) CalcCondAsmCode(Ch[0], Then, NewLabel, Op, nLast0);
                else throw new Exception("Not implemented operator");

				Label(NewLabel);
                CalcCondAsmCode(Ch[1], Then, Else, Op, nLast1);
            }
        }

		public x86DataPosition GetNodePos(ExpressionNode Node, GetNodePosMode Mode = GetNodePosMode.Default)
		{
			var Size = Node.Type.Size;
			var OpNode = Node as OpExpressionNode;
			var FuncScope = Container.FuncScope as x86FuncScopeNode;
			var Data = Node.ArchData as x86NodeData;

			if (Node is LinkingNode)
			{
				var LNode = Node as LinkingNode;
                var LData = LNode.LinkedNode.ArchData as x86LinkedNodeData;
				return LData.Position;
			}

            else if (OpNode != null)
            {
				var Op = OpNode.Operator;
				var Ch = OpNode.Children;
				var Type = OpNode.Type;

				if (Op == Operator.Call)
				{
					if (Mode == GetNodePosMode.Default)
					{
						CalcLinkedNodes(OpNode);
						GetCallExprCode(OpNode);
					}
					else if (Mode == GetNodePosMode.RetNull)
						return null;

					return Node.GetPosition();
				}

				else if (Op == Operator.Index)
				{
					var PtrAddr = GetNodePos(Ch[0]);
					var Offset = GetNodePos(Ch[1]);
					var MulBy = (Ch[1].ArchData as x86NodeData).MulBy;
					return GetIndexNodePos(PtrAddr, Offset, Data.Scope.IndexReg, Mode, Size, MulBy);
				}

				else if (Op == Operator.Assignment)
				{
					if (Mode == GetNodePosMode.Default) GetExprCode(Node);
					else if (Mode == GetNodePosMode.RetNull) return null;
					var Ch0 = OpNode.Children[0] as IdExpressionNode;
					return Ch0.Id.ArchData as x86DataPosition;
				}

				else if (Op == Operator.Member)
				{
					var TmpReg = Data.Scope.TmpReg;
					var SrcPos = GetNodePos(Ch[0], Mode);

					if (Ch[0].Type is ClassType)
					{
						var ClassType = Ch[0].Type as ClassType;
						if (SrcPos is x86MemPosition)
						{
							Append("\tmov " + TmpReg + ", " + SrcPos + "\n");
							SrcPos = TmpReg;
						}

						var InstanceSize = ClassType.VarSize;
						SrcPos = new x86MemPosition(Arch, InstanceSize, SrcPos.ToString(), 0);
					}

					var Splitable = SrcPos as x86SplitablePosition;
					if (Splitable == null) throw new Exception("ERROR");

					var RId = Ch[1] as IdExpressionNode;
					if (RId == null) throw new Exception("ERROR");

                    if (RId.Id is ConstructorFunction)
                    {
                        return RId.Id.ArchData as x86DataPosition;
                    }
					else if (RId.Id is MemberVariable)
					{
						var MemVar = RId.Id as MemberVariable;
						return Splitable.GetPart(MemVar.Offset, Size);
					}
					else if (RId.Id is MemberFunction)
					{
						var MemFunc = RId.Id as MemberFunction;
						var FuncPtrs = Splitable.GetPart(0, Size);

						Append("\tmov " + TmpReg + ", " + FuncPtrs + "\n");
						return new x86MemPosition(Arch, Arch.RegSize, TmpReg.ToString(), MemFunc.Offset);
					}
					else
					{
						throw new Exception("ERROR");
					}
				}
            }
            
            else if (Node is ConstExpressionNode)
            {
				var ConstNode = Node as ConstExpressionNode;
				return new x86ConstPosition(Arch, Size, ConstNode.Value, 0);
            }

			else if (Node is IdExpressionNode)
			{
				var RIdNode = Node as IdExpressionNode;
				return RIdNode.Id.ArchData as x86DataPosition;
			}

			else if (Node is CastExpressionNode && Node.Type is NonFltNumType && Data.Index == -1)
			{
				var CastNode = Node as CastExpressionNode;
				var Ch = CastNode.Child;

				var Src = GetNodePos(Ch, Mode);
				if (Src == null) return null;

				if (Src.Size <= 8)
				{
					var Ret = Node.GetPosition();
					if (Mode == GetNodePosMode.Default)
						MoveData(Ret, Src, Data.Scope, Ch.Type is SignedType);
					else if (Mode == GetNodePosMode.RetNull) return null;
					return Ret;
				}
				else
				{
					throw new NotImplementedException();
				}
			}

			if (Mode == GetNodePosMode.Default) GetExprCode(Node);
			else if (Mode == GetNodePosMode.RetNull) return null;
			return Node.GetPosition();
        }

		private x86DataPosition GetIndexNodePos(x86DataPosition PtrAddr, x86DataPosition Offset,
			x86DataPosition IndexReg, GetNodePosMode Mode, int Size, int MulBy = 1)
		{
			if (PtrAddr.Size != Offset.Size)
				throw new Exception("ERROR");

			x86IndexPosition Ret = null;
			if (PtrAddr is x86MemPosition)
			{
				if (Mode == GetNodePosMode.RetNull) return null;
				if (IndexReg == null) throw new Exception("ERROR");
				Ret = new x86IndexPosition(this, Size, 0, null, PtrAddr, IndexReg);
			}

			if (Offset is x86ConstPosition)
			{
				var ConstOffset = Offset as x86ConstPosition;
				var o = (int)ConstOffset.Unsigned * MulBy;

				if (Ret != null) { Ret.Offset = o; return Ret; }
				return new x86MemPosition(Arch, Size, PtrAddr.ToString(), o);
			}
			else
			{
				var str_Offset = MulBy == 1 ? Offset.ToString() : Offset + " * " + MulBy;
				if (Ret != null) { Ret.str_Offset = str_Offset; return Ret; }
				return new x86MemPosition(Arch, Size, PtrAddr + " + " + str_Offset, 0);
			}
		}

		private void GetCallExprCode(OpExpressionNode OpNode, x86DataPosition ValueTypeRet = null,
			x86DataPosition Self = null, bool RefSelf = false)
		{
            var Data = OpNode.ArchData as x86NodeData;
            var FuncScope = Container.FuncScope as x86FuncScopeNode;
            var FuncData = FuncScope.ArchData as x86FuncContainerData;

			var Ch = OpNode.Children;
			var FuncType = Ch[0].Type as FunctionType;
			var RetType = FuncType.RetType;
			var RetSize = RetType.Size;
            var OldPushedBytes = FuncData.FuncCallPushed;
			var Accumulator = new x86RegPosition(Arch, Arch.RegSize, 0);
			var AsCallParamIndex = 0;

			//-------------------------------------------------------------------------------
			if (Self == null)
			{
				var OpCh0 = Ch[0] as OpExpressionNode;
				if (OpCh0 != null && OpCh0.Operator == Operator.Member)
				{
					var SelfNode = OpCh0.Children[0];
					Self = GetNodePos(SelfNode, GetNodePosMode.StrOnly);
					if (SelfNode.Type is ValueType) RefSelf = true;
				}
			}

			var NCh = Ch;
            var ParamComp = (x86Compiler)null;
			if (FuncType.Conv == CallConv.AsCall)
			{
                ParamComp = Arch.CreateCompiler(State, Container) as x86Compiler;
				NCh = Ch.ToList();

				if (RetType is ValueType)
				{
					if (ValueTypeRet == null) throw new Exception("ERROR");
					ParamComp.GetAddrOf(Arch.GetArgP(ref AsCallParamIndex, Arch.RegSize), ValueTypeRet);
					ValueTypeRet = null;
				}
				else if (ValueTypeRet != null)
				{
					throw new Exception("ERROR");
				}

				if (Self != null)
				{
					var SelfPosition = Arch.GetArgP(ref AsCallParamIndex, !RefSelf ? Self.Size : Arch.RegSize);
					if (!RefSelf) ParamComp.MoveData(SelfPosition, Self, Data.Scope);
					else ParamComp.GetAddrOf(SelfPosition, Self);
					Self = null;
				}

				var Types = FuncType.Params.GetTypes();
				foreach (var e in Arch.EnumFirstAsCallParams(Types, AsCallParamIndex))
				{
					var P = FuncType.Params[e];
					var Node = Ch[e + 1];

                    var Src = ParamComp.GetNodePos(Node);
					var Dst = Arch.GetArgP(ref AsCallParamIndex, P.Type.Size);
                    ParamComp.MoveData(Dst, Src, Data.Scope, P.Type is SignedType);
					NCh.Remove(Node);
				}
			}

			//-------------------------------------------------------------------------------
			var PreAllocatedBytes = 0;
            Ch = NCh;

			for (var i = Ch.Count - 1; i >= 1; i--)
			{
				if (PreAllocatedBytes == 0)
				{
					for (var j = i; j >= 1; j--)
					{
						var Ok = false;
						if (Ch[j].Type is FloatType)
						{
							var nPos = GetNodePos_Float(Ch[j], GetNodePosMode.StrOnly);
							if (nPos == null && !(Ch[i] is ConstExpressionNode)) Ok = true;
						}

						if (Ok) PreAllocatedBytes += Ch[j].Type.Size;
						else break;
					}

					if (PreAllocatedBytes > 0)
					{
						Append("\tsub esp, " + PreAllocatedBytes + "\n");
                        FuncData.FuncCallPushed += PreAllocatedBytes;
					}
				}

				var ChType = Ch[i].Type;
				var OpCh = Ch[i] as OpExpressionNode;
				if (OpCh != null && OpCh.Operator == Operator.Address)
				{
					GetAddrOf(Accumulator, GetNodePos(OpCh.Children[0]), true);
					continue;
				}

				var Pos = (x86DataPosition)null;
				if (ChType is FloatType)
				{
					Pos = GetNodePos_Float(Ch[i]);
					if (Pos == null)
					{
						PreAllocatedBytes -= ChType.Size;
						var TypeStr = x86Architecture.GetTypeString(ChType.Size);
						if (PreAllocatedBytes == 0) Append("\tfstp " + TypeStr + "[esp]\n");
						else Append("\tfstp " + TypeStr + "[esp + " + PreAllocatedBytes + "]\n");
						continue;
					}
				}

				if (Pos == null) Pos = GetNodePos(Ch[i]);
				PushData(Pos);
			}

			//-------------------------------------------------------------------------------
            if (ParamComp != null) Append(ParamComp);

			if (FuncType.Conv != CallConv.AsCall)
			{
				if (Self != null)
				{
					if (!RefSelf) PushData(Self);
					else GetAddrOf(Accumulator, Self, true);
				}

				if (RetType is ValueType)
				{
					if (ValueTypeRet == null) throw new Exception("ERROR");
					GetAddrOf(Accumulator, ValueTypeRet, true);
				}
				else if (ValueTypeRet != null)
				{
					throw new Exception("ERROR");
				}
			}

			//-------------------------------------------------------------------------------
			var FPos = GetNodePos(Ch[0]);
			Append("\tcall " + FPos + "\n");

			if (FuncType.Conv == CallConv.CDecl)
			{
                var s = FuncData.FuncCallPushed - OldPushedBytes;
				if (s > 0) Append("\tadd esp, " + s.ToString() + "\n");
			}

            FuncData.FuncCallPushed = OldPushedBytes;
		}

		void PushData(x86DataPosition Pos)
		{
            var FuncScope = Container.FuncScope as x86FuncScopeNode;
            var FuncData = FuncScope.ArchData as x86FuncContainerData;
			var Parts = GetSplPositions(Pos, Arch.RegSize);

			for (var pi = Parts.Length - 1; pi >= 0; pi--)
			{
				Append("\tpush " + Parts[pi] + "\n");
                FuncData.FuncCallPushed += Arch.RegSize;
			}
		}

		void GetAddrOf(x86DataPosition Dst, x86DataPosition Pos, bool Push = false)
		{
			var MemPos = Pos as x86MemPosition;
			if (MemPos == null || !MemPos.Ref)
				throw new Exception("ERROR");

			var IndexPos = Pos as x86IndexPosition;
			if (IndexPos != null && Push && IndexPos.AllOffset == 0 &&
				string.IsNullOrEmpty(IndexPos.str_Offset))
			{
				Append("\tpush " + IndexPos.Ptr + "\n");
				return;
			}

			Pos = Pos.Extract();
			if (MemPos.AllOffset != 0)
			{
				var OldSize = Pos.Size;
				Pos.Size = 0;
				Append("\tlea " + Dst + ", " + Pos + "\n");

				Pos.Size = OldSize;
				if (Push) Append("\tpush " + Dst + "\n");
			}
			else
			{
				if (!Push)
				{
					var SDst = Dst.ToString();
					if (SDst != MemPos.Name)
						Append("\tmov " + SDst + ", " + MemPos.Name + "\n");

					return;
				}
				
				Append("\tpush " + MemPos.Name + "\n");
			}
		}

		void CalcLinkedNodes(ExpressionNode Node)
		{
			if (Node.LinkedNodes != null)
			{
                var Data = Node.ArchData as x86NodeData;
                foreach (var LNode in Node.LinkedNodes)
				{
					var LData = LNode.ArchData as x86LinkedNodeData;
                    var Src = GetNodePos(LNode.Node);
					var Dst = LData.Position;
                    MoveData(Dst, Src, Data.Scope, LNode.Node.Type is SignedType);
                }
			}
		}

        public override void GetExprCode(ExpressionNode Node)
        {
			// Append("\t; " + Node.Code.String + "\n");
			CalcLinkedNodes(Node);

            if (Node is OpExpressionNode) GetOpExprCode(Node as OpExpressionNode);
            else if (Node is CastExpressionNode) GetCastExprCode(Node as CastExpressionNode);
        }

		private void GetCastExprCode(CastExpressionNode CastNode)
		{
			var T = CastNode.Type;
			if (T is FloatType) GetCastExprCode_Float(CastNode);
			else if (T is BoolType) GetCastExprCode_Bool(CastNode);
			else GetCastExprCode_NonFloat(CastNode);
		}

		private void GetCastExprCode_Bool(CastExpressionNode CastNode)
		{
			var Dst = CastNode.GetPosition();
			var Ch = CastNode.Child;
			var Data = CastNode.ArchData as x86NodeData;

			if (Ch.Type == CastNode.Type)
			{
				if (!MoveAndOp(Dst, Ch))
					MoveData(Dst, GetNodePos(Ch), Data.Scope);
			}
			else
			{
				throw new Exception("ERROR");
			}
		}

		private void GetCastExprCode_NonFloat(CastExpressionNode CastNode)
		{
			var Ch = CastNode.Child;
            var FuncScope = Container.FuncScope as x86FuncScopeNode;
			var Data = CastNode.ArchData as x86NodeData;

			var SrcSize = Ch.Type.Size;
			var DstSize = CastNode.Type.Size;
			var Dst = CastNode.GetPosition();

			if (Ch.Type is FloatType)
			{
				GetNodePos_Float(Ch, LoadIds: true);
				if (Dst != null) FltStore(Dst, Data.Scope, true);
			}
			else if (!MoveAndOp(Dst, Ch))
			{
				var Src = GetNodePos(Ch);
				MoveData(Dst, Src, Data.Scope, Ch.Type is SignedType);
			}

		}

		bool MoveAndOp(x86DataPosition Dst, ExpressionNode Node, bool StrOnly = false)
		{
			var Data = Node.ArchData as x86NodeData;
			var OpNode = Node as OpExpressionNode;
			if (OpNode == null) return false;

			var Ch = OpNode.Children;
			var Op = OpNode.Operator;

			//--------------------------------------------------------------------------------------------
			if (Operators.IsBoolRetOp(Op))
			{
				CalcLinkedNodes(Node);
				if (Operators.IsRelEqualityOp(Op))
				{
					var Type = Ch[0].Type;
					if (Type is NonFltNumType && Type.Size > Arch.RegSize)
					{
						GetExprCondCode_BoolRet(Node, Dst);
					}
					else
					{
						var Str = GetCmpCode(Ch, Data.Scope.TmpReg, Op);
						if (Dst.Size != 1)
						{
							var Dst2 = Dst.Copy(1);
							Append("\tset" + Str + " " + Dst2 + "\n");
							Append("\tand " + Dst + ", 0xFF\n");
						}
						else
						{
							Append("\tset" + Str + " " + Dst + "\n");
						}
					}
				}
				else
				{
					GetExprCondCode_BoolRet(Node, Dst);
				}

				return true;
			}

			//--------------------------------------------------------------------------------------------
			else if (Op == Operator.New)
			{
				CalcLinkedNodes(Node);
				var Type = Node.Type;

				if (Type is TupleType)
				{
					ZeroMem(Dst, Data.Scope);
					return true;
				}
				else if (Type is StructuredType)
				{
					var InitVal = Type.AsmName + "_%InitVal";
					var InitPos = new x86MemPosition(Arch, Type.Size, InitVal, 0);
					MoveData(Dst, InitPos, Data.Scope);

					if (OpNode.Children.Count > 0)
						GetCallExprCode(OpNode, Self: Dst, RefSelf: true);

					return true;
				}
				else
				{
					ZeroMem(Dst, Data.Scope);
					return true;
				}
			}

			//--------------------------------------------------------------------------------------------
			else if (Op == Operator.Call)
			{
				CalcLinkedNodes(Node);
				var Type = Ch[0].Type as FunctionType;
				var RetType = Type.RetType;

				if (RetType is ValueType)
				{
					GetCallExprCode(OpNode, Dst);
					return true;
				}
			}

			//--------------------------------------------------------------------------------------------
			else if (Op == Operator.Add || Op == Operator.Multiply || Operators.IsBitwiseOp(Op))
			{
				var ChDst = GetNodePos(Ch[0], GetNodePosMode.StrOnly);
				var ChSrc = GetNodePos(Ch[1], GetNodePosMode.StrOnly);

				if (ChSrc.IsEqual(Dst) && (!(Dst is x86MemPosition) || Data.DataCalcPos.HasFlag(x86DataCalcPos.Memory)))
				{
					CalcLinkedNodes(Node);
					if (!StrOnly)
					{
						GetNodePos(Ch[0]);
						GetNodePos(Ch[1]);
					}

					GetOpBaseCode_NonFloat(Op, Dst, ChDst, Data.Scope.TmpReg,
						Ch[0].Type is SignedType, OpNode.Reverse);

					return true;
				}
			}

			return false;
		}

		x86DataPosition[] GetSplPositions(x86DataPosition Pos, int Size)
		{
			if (Pos is x86SplitablePosition)
			{
				var Spl = Pos as x86SplitablePosition;
				return Spl.Split(Size);
			}
			else
			{
				return new x86DataPosition[] { Pos };
			}
		}

        public void ZeroMem(x86DataPosition Dst, x86ExprScope Scope)
		{
			Dst = Dst.Extract();

			if (Dst.Size > Arch.RegSize && Dst.Size % 4 == 0)
			{
				var SSEReg = Scope.SSETmpReg;
				Append("\tpxor " + SSEReg + ", " + SSEReg + "\n");
				ZeroMemSSE(Dst, Scope);
			}
			else
			{
				var TmpReg = Scope.TmpReg;
				Append("\txor " + TmpReg + ", " + TmpReg + "\n");
				ZeroMemGeneral(Dst, Scope);
			}
		}

		void ZeroMemSSE(x86DataPosition Dst, x86ExprScope Scope)
		{
			var Size = Dst.Size;
			if (Size < 16)
			{
				var P2 = (int)Helper.Pow2((uint)Size);
				if (P2 != Size) Size = P2 / 2;
			}

			var DstParts = GetSplPositions(Dst, Size);
			var SSEReg = Scope.SSETmpReg;

			foreach (var D in DstParts)
			{
				if (D.Size == 16) Append((AlignedSSE(D) ? "\tmovdqa " : "\tmovdqu ") + D + ", " + SSEReg + "\n");
				else if (D.Size == 8) Append("\tmovq " + D + ", " + SSEReg + "\n");
				else if (D.Size == 4) Append("\tmovd " + D + ", " + SSEReg + "\n");
				else ZeroMemGeneral(D, Scope);
			}
		}

		void ZeroMemGeneral(x86DataPosition Dst, x86ExprScope Scope)
		{
			var DstParts = GetSplPositions(Dst, Arch.RegSize);
			var TmpReg = Scope.TmpReg;

			foreach (var D in DstParts)
				Append("\tmov " + D + ", " + TmpReg + "\n");
		}

		public void MoveData(x86DataPosition Dst, x86DataPosition Src, x86ExprScope Scope,
			bool SrcSigned = false, string Cond = null)
		{
			Dst = Dst.Extract();
			Src = Src.Extract();

			var DstSrcEqu = Src.IsEqual(Dst, false);
			if (Dst.Size > Src.Size || !DstSrcEqu)
			{
				if (CanUseSSEMove(Dst, Src))
				{
					if (Cond != null) throw new Exception("ERROR");
					MoveDataSSE(Dst, Src, Scope);
				}
				else if (Dst.Size > Arch.RegSize)
				{
					if (Cond != null) throw new Exception("ERROR");
					MoveDataMultiParts(Dst, Src, Scope, SrcSigned);
				}
				else
				{
					MoveDataSinglePart(Dst, Src, Scope, SrcSigned, DstSrcEqu, Cond);
				}
			}
		}

		private bool CanUseSSEMove(x86DataPosition Dst, x86DataPosition Src)
		{
			if (!(Dst is x86MemPosition || Dst is x86SSERegPosition)) return false;
			else if (!(Src is x86MemPosition || Src is x86SSERegPosition)) return false;
			else if (Dst.Size <= Arch.RegSize || Dst.Size != Src.Size) return false;
			else return true;
		}

		private bool AlignedSSE(x86DataPosition D)
		{
			var MemD = D as x86MemPosition;
			return MemD != null && MemD.Align == 16;
		}

		private bool AlignedSSE(x86DataPosition D, x86DataPosition S)
		{
			return AlignedSSE(D) && AlignedSSE(S);
		}

		void MoveDataSSE(x86DataPosition Dst, x86DataPosition Src, x86ExprScope Scope)
		{
			var Size = Dst.Size;
			if (Size < 16)
			{
				var P2 = (int)Helper.Pow2((uint)Size);
				if (P2 != Size) Size = P2 / 2;
			}

			var DstParts = GetSplPositions(Dst, Size);
			var SrcParts = GetSplPositions(Src, Size);

			for (var i = 0; i < DstParts.Length; i++)
			{
				var D = DstParts[i];
				var S = SrcParts[i];

				if (D.Size == 16) StdMem2MemOp(AlignedSSE(D, S) ? "\tmovdqa " : "\tmovdqu ", D, S, Scope.SSETmpReg);
				else if (D.Size == 8) StdMem2MemOp("\tmovq ", D, S, Scope.SSETmpReg);
				else if (D.Size == 4) StdMem2MemOp("\tmovd ", D, S, Scope.SSETmpReg);
				else if (D.Size % 4 == 0) MoveDataSSE(D, S, Scope);
				else MoveDataSinglePart(D, S, Scope);
			}
		}

		void MoveDataSinglePart(x86DataPosition Dst, x86DataPosition Src, x86ExprScope Scope,
			bool SrcSigned = false, bool DstSrcEqu = false, string Cond = null)
		{
			var SrcSize = Src.Size;
			var DstSize = Dst.Size;

			if (Cond != null)
			{
				if (DstSize != SrcSize) throw new Exception("ERROR");
				else StdMem2MemOp("\tcmov" + Cond + " ", Dst, Src, Scope.TmpReg);
				return;
			}

			var ConstSrc = Src as x86ConstPosition;
			if (ConstSrc != null && ConstSrc.Unsigned == 0 && !(Dst is x86MemPosition))
			{
				Append("\txor " + Dst + ", " + Dst + "\n");
			}
			else
			{
				string Ins;
				if (DstSize > SrcSize && ConstSrc == null)
				{
					if (SrcSigned) Ins = "\tmovsx ";
					else Ins = "\tmovzx ";
				}
				else
				{
					Ins = "\tmov ";
					Src.Size = DstSize;
				}

				Dst.Size = DstSize;
				if (Ins == "\tmovzx " && DstSrcEqu)
					Append("\tand " + Dst + ", 0x" + Helper.Str_SizeMask[SrcSize] + "\n");
				else StdMem2MemOp(Ins, Dst, Src, Scope.TmpReg);
			}
		}

		void MoveDataMultiParts(x86DataPosition Dst, x86DataPosition Src,
			x86ExprScope Scope, bool SrcSigned = false)
		{
			var MovIns = "\tmovzx ";
			if (SrcSigned) MovIns = "\tmovsx ";

			var RegSize = Arch.RegSize;
			var Accumulator = new x86RegPosition(Arch, Arch.RegSize, 0);

			var DstParts = GetSplPositions(Dst, Arch.RegSize);
			var SrcParts = GetSplPositions(Src, Arch.RegSize);

			for (var i = 0; i < DstParts.Length; i++)
			{
				var D = DstParts[i];
				if (i >= SrcParts.Length)
				{
					if (!SrcSigned) Append("\tmov " + D + ", 0\n");
					else if (!x86Architecture.IsRegPos(D, 2))
						Append("\tmov " + D + ", " + x86Architecture.RegStr(2, D.Size) + "\n");
				}
				else
				{
					x86DataPosition S = SrcParts[i];
					if (SrcSigned && i == SrcParts.Length - 1 && DstParts.Length > SrcParts.Length)
					{
						if (S.Size < RegSize) Append(MovIns + Accumulator + ", " + S + "\n");
						else if (!Accumulator.IsEqual(S)) Append("\tmov " + Accumulator + ", " + S + "\n");
						Append("\tcdq\n");

						S = new x86RegPosition(Arch, RegSize, 0);
					}

					var ConstSrc = S as x86ConstPosition;
					if (ConstSrc != null && ConstSrc.Unsigned == 0 && !(D is x86MemPosition))
					{
						Append("\txor " + D + ", " + D + "\n");
					}
					else
					{
						if (D.Size > S.Size) StdMem2MemOp(MovIns, D, S, Scope.TmpReg);
						else if (!D.IsEqual(S)) StdMem2MemOp("\tmov ", D, S, Scope.TmpReg);
					}
				}
			}
		}

		private x86DataPosition Mem2Mem(x86DataPosition D, x86DataPosition S, x86DataPosition TmpReg)
		{
			if (D is x86MemPosition && S is x86MemPosition && TmpReg != null)
			{
				TmpReg.Size = S.Size;
				if (TmpReg is x86SSERegPosition)
				{
					if (S.Size == 16) Append("\tmovdqu " + TmpReg + ", " + S + "\n");
					else if (S.Size == 8) Append("\tmovq " + TmpReg + ", " + S + "\n");
					else if (S.Size == 4) Append("\tmovd " + TmpReg + ", " + S + "\n");
				}
				else
				{
					Append("\tmov " + TmpReg + ", " + S + "\n");
				}

				S = TmpReg;
			}

			return S;
		}

		private void StdMem2MemOp(string Op, x86DataPosition D, x86DataPosition S, x86DataPosition TmpReg)
		{
			S = Mem2Mem(D, S, TmpReg);
			Append(Op + D + ", " + S + "\n");
		}

		private void FltLoad(x86DataPosition Src, x86ExprScope Scope, bool Int)
		{
			if (!(Src is x86MemPosition))
			{
				var NSrc = Scope.TmpMem.Copy(Src.Size);
				MoveData(NSrc, Src, Scope);
				Src = NSrc;
			}

			if (Int) Append("\tfild " + Src + "\n");
			else Append("\tfld " + Src + "\n");
		}

		private void FltStore(x86DataPosition Dst, x86ExprScope Scope, bool Int)
		{
			var NDst = Dst;
			if (!(Dst is x86MemPosition))
				NDst = Scope.TmpMem.Copy(Dst.Size);

			if (Int) Append("\tfistp " + NDst + "\n");
			else Append("\tfstp " + NDst + "\n");
			if (NDst != Dst) MoveData(Dst, NDst, Scope);
		}

		private void GetCastExprCode_Float(CastExpressionNode CastNode)
		{
			var Data = CastNode.ArchData as x86NodeData;
			var Ch = CastNode.Child;
			var Src = GetNodePos(Ch);

            var FuncScope = Container.FuncScope as x86FuncScopeNode;
			var DstOut = Data.Output;
			var Dst = DstOut == null ? null : CastNode.GetPosition();

            if (!x86Architecture.NeedLoadFloatDst(Ch, true))
			{
				if (Ch.Type is NonFltNumType) FltLoad(Src, Data.Scope, true);
				if (Dst != null) FltStore(Dst, Data.Scope, false);
			}
			else
			{
				if (Ch is ConstExpressionNode)
				{
					if (Dst == null)
					{
						var ConstCh = Ch as ConstExpressionNode;
						LoadFltConst(ConstCh);
						return;
					}
					else
					{
						Append("\tmov " + Dst + ", " + Src + "\n");
						Src = Dst;
						Dst = null;
					}
				}

				if (Dst == null || !Dst.IsEqual(Src))
				{
					FltLoad(Src, Data.Scope, Ch.Type is NonFltNumType);
					if (Dst != null) FltStore(Dst, Data.Scope, false);
				}
			}
		}

		private void GetOpExprCode(OpExpressionNode OpNode)
		{
			var Op = OpNode.Operator;
			var Ch = OpNode.Children;
			var Data = OpNode.ArchData as x86NodeData;

            if (Op == Operator.CreateTuple)
            {
                if (Data.Index != -1)
                {
                    var Type = OpNode.Type as ValueType;
                    if (Type == null) throw new Exception("ERROR");
                    var ChIndex = 0;
                    var Dst = OpNode.GetPosition();
                    var SDst = Dst as x86SplitablePosition;

                    foreach (var e in Type.Members)
                        if (e is MemberVariable)
                        {
                            var MemVar = e as MemberVariable;
                            var SrcNode = Ch[ChIndex];
                            var DstP = SDst.GetPart(MemVar.Offset, MemVar.Type.Size);

                            if (SrcNode.Type is FloatType)
                            {
                                GetNodePos_Float(SrcNode, LoadIds: true);
                                FltStore(DstP, Data.Scope, MemVar.Type is NonFltNumType);
                            }
                            else
                            {
                                var Src = GetNodePos(SrcNode);
                                MoveData(DstP, Src, Data.Scope, MemVar.Type is SignedType);
                            }

                            ChIndex++;
                        }
                }
                else
                {
                    foreach (var e in Ch)
                        GetExprCode(e);
                }
            }
			else if (Op == Operator.Condition)
			{
				var OpCondition = Ch[0] as OpExpressionNode;
				var EnableMoveBranch = Operators.IsRelEqualityOp(OpCondition.Operator);

                var Glb = Container.GlobalScope;
				var T = Arch.GetNodeCondBrach(this, Glb, Ch[1], true, EnableMoveBranch: EnableMoveBranch);
				var E = Arch.GetNodeCondBrach(this, Glb, Ch[2], false, EnableMoveBranch: EnableMoveBranch);
				GetConditionCode(Ch[0], T, E);
			}
			else if (Op == Operator.Call)
			{
				GetCallExprCode(OpNode);
			}
			else
			{
				if (OpNode.Type is FloatType) GetOpBaseCode_Float(OpNode);
				else GetOpBaseCode_NonFloat(OpNode);
			}
		}

		private void GetExprCondCode_BoolRet(ExpressionNode Node, x86DataPosition Dst)
		{
			var Type = Node.Type as BoolType;
            var FuncScope = Container.FuncScope as x86FuncScopeNode;
			var Data = Node.ArchData as x86NodeData;

			var Then = new x86MoveCondBranch(Dst, new x86ConstPosition(Arch, Dst.Size, Type.TrueData, 0), Data.Scope);
			var Else = new x86MoveCondBranch(Dst, new x86ConstPosition(Arch, Dst.Size, Type.FalseData, 0), Data.Scope);
			GetConditionCode(Node, Then, Else, LinkedNodesCalced: true);
		}

		x86DataPosition GetNodePos_Float(ExpressionNode Node, GetNodePosMode Mode = GetNodePosMode.Default, bool LoadIds = false)
		{
			var Data = Node.ArchData as x86NodeData;
			if (Node is ConstExpressionNode)
			{
				var ConstNode = Node as ConstExpressionNode;
				if (Mode == GetNodePosMode.Default)
					LoadFltConst(ConstNode);

				return null;
			}
			else if (Node is IdExpressionNode)
			{
				var RIdNode = Node as IdExpressionNode;
				var Pos = RIdNode.Id.ArchData as x86DataPosition;

				if (LoadIds)
				{
					if (Mode == GetNodePosMode.RetNull) return null;
					else if (Mode == GetNodePosMode.StrOnly) return Pos;
					FltLoad(Pos, Data.Scope, Node.Type is NonFltNumType);
				}

				return Pos;
			}
			else
			{
				if (Mode == GetNodePosMode.RetNull) return null;
                var Pos = GetNodePos(Node, Mode);

				if (LoadIds && Pos != null)
				{
					if (Mode == GetNodePosMode.RetNull) return null;
					else if (Mode == GetNodePosMode.StrOnly) return Pos;
					FltLoad(Pos, Data.Scope, Node.Type is NonFltNumType);
				}

				return Pos;
			}
		}

		private void LoadFltConst(ConstExpressionNode ConstCh)
		{
			var V = ConstCh.Double;
			if (V == 0.0) Append("\tfldz\n");
			else if (V == 1.0) Append("\tfld1\n");
			else if (V == Math.PI) Append("\tfldpi\n");
			else throw new Exception("ERROR");
		}

		private void GetOpBaseCode_Float(OpExpressionNode OpNode)
		{
			var Data = OpNode.ArchData as x86NodeData;
			var Ch = OpNode.Children;

			switch (OpNode.Operator)
			{
				case Operator.Assignment:
					var RetVar = false;
					if (Ch[0] is IdExpressionNode)
					{
						var IdCh0 = Ch[0] as IdExpressionNode;
						var Id = IdCh0.Id as LocalVariable;
						if (Id != null && Id.RetVar) RetVar = true;
					}

					var ConstNode = Ch[1] as ConstExpressionNode;
					if (!RetVar)
					{
						var Dst = GetNodePos(Ch[0]);
						if (ConstNode != null)
						{
							var Value = ConstNode != null ? ConstNode.Value : null;
							var Src = new x86ConstPosition(Arch, Ch[1].Type.Size, Value, 0);
							MoveData(Dst, Src, Data.Scope);
						}
						else
						{
							GetNodePos_Float(Ch[1], LoadIds: true);
							FltStore(Dst, Data.Scope, false);
						}
					}
					else
					{
						GetNodePos_Float(Ch[1], LoadIds: true);
					}

					break;

				case Operator.Neg:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfchs\n");
					break;

				case Operator.Abs:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfabs\n");
					break;

				case Operator.Sqrt:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfsqrt\n");
					break;

				case Operator.Sin:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfsin\n");
					break;

				case Operator.Cos:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfcos\n");
					break;

				case Operator.Tan:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfptan\n");
					Append("\tffree st0\n");
					Append("\tfincstp\n");
					break;

				case Operator.ATan:
					GetNodePos_Float(Ch[0], LoadIds: true);
					Append("\tfld1\n");
					Append("\tfpatan\n");
					break;

				case Operator.ATan2:
					GetNodePos_Float(Ch[0], LoadIds: true);
					GetNodePos_Float(Ch[1], LoadIds: true);
					Append("\tfpatan\n");
					break;

				default:
					if (Operators.IsBitArithmOp(OpNode.Operator))
						GetShiftArithmCode_Float(OpNode);
					else
						throw new Exception("Unknown operator");

					break;
			}
		}

		private void GetShiftArithmCode_Float(OpExpressionNode OpNode)
		{
			var Ch = OpNode.Children;
			var Dst = GetNodePos_Float(Ch[0]);
			var Src = GetNodePos_Float(Ch[1]);
			var Op = OpNode.Operator;

			var OpStr = "";
			if (Op == Operator.Add) OpStr = "add";
			else if (Op == Operator.Subract) OpStr = "sub";
			else if (Op == Operator.Multiply) OpStr = "mul";
			else if (Op == Operator.Divide) OpStr = "div";
			else throw new NotImplementedException();

			if (Dst != null)
			{
				if (Src != null) throw new Exception("ERROR");
				var Reverse = !OpNode.Reverse && (Op == Operator.Subract || Op == Operator.Divide);
				FloatOp(OpStr, Dst, Ch[1].Type is FloatType, Reverse);
			}
			else
			{
				FloatOp(OpStr, Src, Ch[1].Type is FloatType, OpNode.Reverse);
			}
		}

		private void FloatOp(string Op, x86DataPosition Src, bool Float, bool Reverse)
		{
			if (Src == null)
			{
				if (!Reverse) Append("\tf" + Op + "p\n");
				else Append("\tf" + Op + "rp\n");
				return;
			}

			if (Float)
			{
				if (!Reverse) Append("\tf" + Op + " " + Src + "\n");
				else Append("\tf" + Op + "r " + Src + "\n");
			}
			else
			{
				if (!Reverse) Append("\tfi" + Op + " " + Src + "\n");
				else Append("\tfi" + Op + "r " + Src + "\n");
			}
		}

		private void GetOpBaseCode_NonFloat(Operator Op, x86DataPosition Dst, x86DataPosition Src,
			x86DataPosition TmpReg, bool Signed, bool Reverse)
		{
			if (Reverse)
			{
				var Tmp = Dst;
				Dst = Src;
				Src = Tmp;
			}

			var SplDst = GetSplPositions(Dst, Arch.RegSize);
			var SplSrc = GetSplPositions(Src, Arch.RegSize);

			if (SplDst != null && SplSrc != null)
			{
				if (SplDst.Length != SplSrc.Length)
					throw new Exception("ERROR");
			}

			switch (Op)
			{
				case Operator.Neg:
					if (SplDst.Length == 1) Append("\tneg " + SplDst[0] + "\n");
					else throw new Exception("ERROR");
					break;

				case Operator.Complement:
					EachPart(SplDst, SplSrc, TmpReg, "not");
					break;

				case Operator.Add:
				case Operator.Subract:
					var Val = GetVal(Src);
					AddSubData(SplDst, SplSrc, TmpReg, Val, Op);
					break;

				case Operator.Multiply:
					if (SplSrc.Length == 1)
					{
						var OldDst = Dst;
						if (Dst is x86MemPosition)
						{
							Append("\tmov " + TmpReg + ", " + Dst + "\n");
							Dst = TmpReg;
						}

						if (x86Architecture.IsRegPos(Dst, 0) && !(Src is x86ConstPosition))
							Append("\timul " + Src + "\n");
						else Append("\timul " + Dst + ", " + Src + "\n");

						if (Dst != OldDst) Append("\tmov " + OldDst + ", " + Dst + "\n");
					}
					else
					{
						throw new NotImplementedException();
					}

					break;

				case Operator.Divide:
				case Operator.Modolus:
					DivModData(SplDst, SplSrc, Signed);
					break;

				case Operator.BitwiseAnd:
					EachPart(SplDst, SplSrc, TmpReg, "and");
					break;
					
				case Operator.BitwiseOr:
					EachPart(SplDst, SplSrc, TmpReg, "or");
					break;
					
				case Operator.BitwiseXor:
					EachPart(SplDst, SplSrc, TmpReg, "xor");
					break;

				case Operator.ShiftLeft:
					if (SplDst.Length == 1)
					{
						StdMem2MemOp("\tshl ", SplDst[0], SplSrc[0], TmpReg);
					}
					else
					{
						throw new NotImplementedException();
					}

					break;

				case Operator.ShiftRight:
					if (SplDst.Length == 1)
					{
						if (!Signed) StdMem2MemOp("\tshr ", SplDst[0], SplSrc[0], TmpReg);
						else StdMem2MemOp("\tsar ", SplDst[0], SplSrc[0], TmpReg);
					}
					else
					{
						throw new NotImplementedException();
					}

					break;

				default:
					throw new NotImplementedException();
			}
		}

		private void EachPart(x86DataPosition[] SplDst, x86DataPosition[] SplSrc, x86DataPosition TmpReg, string Ins)
		{
			Ins = "\t" + Ins + " ";
			if (SplSrc != null)
			{
				for (var i = 0; i < SplDst.Length; i++)
					StdMem2MemOp(Ins, SplDst[i], SplSrc[i], TmpReg);
			}
			else
			{
				for (var i = 0; i < SplDst.Length; i++)
					Append(Ins + SplDst[i] + "\n");
			}
		}

		private void DivModData(x86DataPosition[] SplDst, x86DataPosition[] SplSrc, bool Signed)
		{
			if (SplDst.Length == 1)
			{
				var Dst0 = SplDst[0];
				var Src0 = SplSrc[0];

				var Size = Dst0.Size;
				if (Size == 1) Dst0.Size = 2;

				if (!x86Architecture.IsRegPos(Dst0, 0))
				{
					var Accumulator = x86Architecture.RegStr(0, Size);
					Append("\tmov " + Accumulator + ", " + Dst0 + "\n");
				}

				if (!Signed)
				{
					if (Size == 1)
					{
						Append("\txor ah, ah\n"); 
					}
					else
					{
						var EDX = x86Architecture.RegStr(2, Size);
						Append("\txor " + EDX + ", " + EDX + "\n");
					}

					Append("\tdiv " + Src0 + "\n");
				}
				else
				{
					if (Size == 1) Append("\tcbw\n");
					else if (Size == 2) Append("\tcwd\n");
					else if (Size == 4) Append("\tcdq\n");
					else if (Size == 8) Append("\tcqo\n");
					else throw new Exception("ERROR");

					Append("\tidiv " + Src0 + "\n");
				}
			}
			else
			{
				throw new NotImplementedException();
			}
		}

		private void AddSubData(x86DataPosition[] SplDst, x86DataPosition[] SplSrc, x86DataPosition TmpReg, ulong Val, Operator Op)
		{
			if (Val != 0)
			{
				if (SplDst.Length == 1 && Val == 1)
				{
					if (Op == Operator.Add) Append("\tinc " + SplDst[0] + "\n");
					else if (Op == Operator.Subract) Append("\tdec " + SplDst[0] + "\n");
					else throw new NotImplementedException();
				}
				else
				{
					for (var i = 0; i < SplDst.Length; i++)
					{
						string Ins;
						if (Op == Operator.Add) Ins = i == 0 ? "\tadd " : "\tadc ";
						else if (Op == Operator.Subract) Ins = i == 0 ? "\tsub " : "\tsbb ";
						else throw new NotImplementedException();

						StdMem2MemOp(Ins, SplDst[i], SplSrc[i], TmpReg);
					}
				}
			}
		}

		private void GetOpBaseCode_NonFloat(OpExpressionNode OpNode)
		{
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;
			var Dst = GetNodePos(Ch[0]);
			var Data = OpNode.ArchData as x86NodeData;

			if (Op == Operator.Assignment)
			{
				if (!MoveAndOp(Dst, Ch[1]))
				{
					var Src = GetNodePos(Ch[1]);
					MoveData(Dst, Src, Data.Scope, Ch[1].Type is SignedType);
				}
			}
			else if (Op == Operator.Neg)
			{
				var Spl = GetSplPositions(Dst, Arch.RegSize);
				for (var i = 0; i < Spl.Length; i++)
				{
					var P = Spl[i];
					if (i > 0) Append("\tadc " + P + ", 0\n");
					Append("\tneg " + P + "\n");
				}
			}
			else if (Op == Operator.Address)
			{
				var Src = Dst;
				Dst = GetNodePos(OpNode, GetNodePosMode.StrOnly);
				GetAddrOf(Dst, Src);
			}
			else
			{
				x86DataPosition Src = null;
				if (Ch.Count > 1) Src = GetNodePos(Ch[1]);

				GetOpBaseCode_NonFloat(Op, Dst, Src, Data.Scope.TmpReg, Ch[0].Type is SignedType, OpNode.Reverse);
			}
		}

		private static ulong GetVal(x86DataPosition Src)
		{
			var ConstSrc = Src as x86ConstPosition;
			return ConstSrc != null ? ConstSrc.Unsigned : ulong.MaxValue;
		}

        public override bool Compile(CompilerState State, PString[] Lines)
		{
			State.Reset();
            var PreState = new PreprocessorState(new MessageCollector(State.Messages));
			var GlobalScope = new GlobalScopeNode(PreState, State, Lines);

            var RetValue = GlobalScope.Process();
            if (!PreState.CheckConditions()) RetValue = false;

            if (RetValue) GetAsmCode(State, GlobalScope);
			LibraryLoader.SaveLibrary(@"Txt\Lib.aslib", GlobalScope);
			return RetValue;
        }

		private void GetAsmCode(CompilerState State, GlobalScopeNode GlobalScope)
		{
			if (State.Format == ImageFormat.MSCoff)
			{
				if (Arch.x86_64)
					Append("\tformat MS64 COFF\n");
				else Append("\tformat MS COFF\n");
			}
			else if (State.Format == ImageFormat.GUI)
			{
				if (Arch.x86_64)
					Append("\tformat PE64 GUI 4.0\n");
				else Append("\tformat PE GUI 4.0\n");
			}
			else if (State.Format == ImageFormat.Console)
			{
				if (Arch.x86_64)
					Append("\tformat PE64 CONSOLE 4.0\n");
				else Append("\tformat PE CONSOLE 4.0\n");
			}
			else if (State.Format == ImageFormat.DLL || State.Format == ImageFormat.AsDLL)
			{
				if (Arch.x86_64)
					Append("\tformat PE64 DLL 4.0\n");
				else Append("\tformat PE DLL 4.0\n");
			}
			else
			{
				throw new Exception("ERROR");
			}

			var ExternCode = GlobalScope.GetExternCode();
			if (ExternCode.Length > 0) Append(ExternCode);

			var Entry = GlobalScope.GetEntry();
			if (Entry != null)
			{
				if (State.Format == ImageFormat.MSCoff)
					Append("\tpublic " + Entry.AsmName + "\n");
				else Append("\tentry " + Entry.AsmName + "\n");
			}

			Append("\t\n");

			// -----------------------------------------------------------------
			Append("section \"code\" code readable executable\n\n");
			GlobalScope.GetAsmCode(this, GetAsmCodeMode.Code);

			// -----------------------------------------------------------------
			var DataCompiler = Arch.CreateCompiler(State);
			GlobalScope.GetAsmCode(DataCompiler, GetAsmCodeMode.Data);
			var DataCode = DataCompiler.GetAssembly();

			if (DataCode.Length > 0)
			{
				Append("section \"data\" data readable writeable\n\n");
				Append(DataCode);
			}

			// -----------------------------------------------------------------
			var ImportCode = GlobalScope.GetImportCode();
			if (ImportCode.Length > 0)
			{
				Append("section \"idata\" import data readable writeable\n\n");
				Append(ImportCode);
			}

		}

    }
}

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