Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Bird Programming Language: Part 3

, 1 Jan 2013 GPL3
A new general purpose language that aims to be fast, high level and simple to use.
Bird-noexe.zip
Bird
Archives
crt2.o
crtbegin.o
crtend.o
libadvapi32.a
libcomctl32.a
libcomdlg32.a
libgcc.a
libgdi32.a
libglu32.a
libkernel32.a
libmingw32.a
libmingwex.a
libmoldname.a
libmsvcrt.a
libopengl32.a
libshell32.a
libstdc++.a
libuser32.a
libwinmm.a
libwsock32.a
Libraries
BirdCore
Array.bird
BigInteger.bird
BinaryRW.bird
BirdCore.a
BirdCore.blib
CategoryData.dat
Console.bird
Convert.bird
Debug.bird
Entry.bird
Environment.bird
Exception.bird
Float.bird
LEB128.bird
Math.bird
Memory.bird
Object.bird
Random.bird
Reflection.bird
StandardC.bird
Stream.bird
String.bird
ToLowerData.dat
ToUpperData.dat
Types.bird
ValueType.bird
Win32.bird
x86Helper.bird
BlitzMax
.bmx
Launcher.bmx.gui.release.win32.x86.o
appstub.release.win32.x86.a
bank.release.win32.x86.a
bankstream.release.win32.x86.a
blitz.release.win32.x86.a
BlitzMax.a
BlitzMax.bird
BlitzMax.blib
d3d7max2d.release.win32.x86.a
d3d9max2d.release.win32.x86.a
directx.release.win32.x86.a
dxgraphics.release.win32.x86.a
event.release.win32.x86.a
filesystem.release.win32.x86.a
font.release.win32.x86.a
glgraphics.release.win32.x86.a
glmax2d.release.win32.x86.a
graphics.release.win32.x86.a
hook.release.win32.x86.a
keycodes.release.win32.x86.a
Launcher.bmx
libpng.release.win32.x86.a
linkedlist.release.win32.x86.a
math.release.win32.x86.a
max2d.release.win32.x86.a
opengl.release.win32.x86.a
pixmap.release.win32.x86.a
pngloader.release.win32.x86.a
polledinput.release.win32.x86.a
standardio.release.win32.x86.a
stdc.release.win32.x86.a
stream.release.win32.x86.a
system.release.win32.x86.a
textstream.release.win32.x86.a
win32.release.win32.x86.a
zlib.release.win32.x86.a
PrgLinec.bmx
Samples
Circles
Circles.bird
CppMain.bird
Fire
Fire.bird
Higher Order Functions
C#
Higher Order Functions.v11.suo
Properties
Test.bird
msvcrt.lib
Reflection
Reflection.bird
Squares
Squares.bird
Template
Template.bird
Source
Base
Bird.v11.suo
Expressions
Identifiers
Languages
NativeCode
Properties
Recognizers
Expressions
Scopes
x86
Thumbs.db
Bird.zip
crt2.o
crtbegin.o
crtend.o
libadvapi32.a
libcomctl32.a
libcomdlg32.a
libgcc.a
libgdi32.a
libglu32.a
libkernel32.a
libmingw32.a
libmingwex.a
libmoldname.a
libmsvcrt.a
libopengl32.a
libshell32.a
libstdc++.a
libuser32.a
libwinmm.a
libwsock32.a
Binaries
ar.exe
Bird.exe
fasm.exe
ld.exe
libiconv-2.dll
libintl-8.dll
Array.bird
BigInteger.bird
BinaryRW.bird
BirdCore.a
BirdCore.blib
CategoryData.dat
Console.bird
Convert.bird
Debug.bird
Entry.bird
Environment.bird
Exception.bird
Float.bird
LEB128.bird
Math.bird
Memory.bird
Object.bird
Random.bird
Reflection.bird
StandardC.bird
Stream.bird
String.bird
ToLowerData.dat
ToUpperData.dat
Types.bird
ValueType.bird
Win32.bird
x86Helper.bird
Launcher.bmx.gui.release.win32.x86.o
appstub.release.win32.x86.a
bank.release.win32.x86.a
bankstream.release.win32.x86.a
blitz.release.win32.x86.a
BlitzMax.a
BlitzMax.bird
BlitzMax.blib
d3d7max2d.release.win32.x86.a
d3d9max2d.release.win32.x86.a
directx.release.win32.x86.a
dxgraphics.release.win32.x86.a
event.release.win32.x86.a
filesystem.release.win32.x86.a
font.release.win32.x86.a
glgraphics.release.win32.x86.a
glmax2d.release.win32.x86.a
graphics.release.win32.x86.a
hook.release.win32.x86.a
keycodes.release.win32.x86.a
Launcher.bmx
libpng.release.win32.x86.a
linkedlist.release.win32.x86.a
math.release.win32.x86.a
max2d.release.win32.x86.a
opengl.release.win32.x86.a
pixmap.release.win32.x86.a
pngloader.release.win32.x86.a
polledinput.release.win32.x86.a
standardio.release.win32.x86.a
stdc.release.win32.x86.a
stream.release.win32.x86.a
system.release.win32.x86.a
textstream.release.win32.x86.a
win32.release.win32.x86.a
zlib.release.win32.x86.a
PrgLinec.bmx
PrgLinec.exe
Circles.bird
CppMain.bird
Fire.bird
Higher Order Functions.v11.suo
Test.bird
msvcrt.lib
Reflection.bird
Squares.bird
Template.bird
Bird.v11.suo
Thumbs.db
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bird.NativeCode;

namespace Bird.x86
{
	public class x86ReturnVariable : LocalVariable
	{
		public x86ReturnVariable(IdContainer Container, CodeString Name, Type Type)
			: base(Container, Name, Type)
		{
		}
	}

	public class x86IdContainerData
	{
		public IdContainer Container;
		public x86DataList UsedByParams;
		public x86DataAllocator Allocator;

		public x86IdContainerData(IdContainer Container)
		{
			this.Container = Container;
		}

		public void Reset()
		{
			if (Allocator == null) Allocator = new x86DataAllocator(Container);
			if (UsedByParams == null) UsedByParams = new x86DataList(Allocator.Arch);

			Allocator.Reset();
			UsedByParams.Reset();
		}
	}

    [Flags]
    public enum x86FuncScopeFlags : byte
    {
        None = 0,
		FunctionCalled = 1,
		SaveFramePointer = 2,
		SaveParameterPointer = 4,
        RetAddressInParams = 8,
		StackLocationsValid = 16,
    }

	public class x86FuncScopeData : x86IdContainerData
	{
		public x86ReturnVariable ReturnVariable;
		public x86DataList UsedToPassParams;
		public AutoAllocatedList<LocalVariable> AllParams;
        public x86FuncScopeFlags Flags;
		//public bool DisableAlwaysReturned;
		//public LocalVariable AlwaysReturned;

		public List<ExpressionNode> Expressions;
		public int PushedRegisters;
		public int CallParameters;
		public int SubractedFromESP;
		public int UnallocatedSpace;
		public int StackAlignment = 1;

		public x86DataList DisabledLocations;
		public x86GRegLocation StackPointer;
		public x86GRegLocation FramePointer;
		public x86GRegLocation ParameterPointer;

		public AutoAllocatedList<x86MoveStruct> FuncLeaveLoadRegs;
		public x86DataLocation SpaceForSaving;
		public int FuncLeaveInsCount;

		public x86FuncScopeData(FunctionScope Scope)
			: base(Scope)
		{
		}
	}

	public class x86FunctionData : x86IdentifierData
	{
		public string Assembly;
		public bool AssemblyOnly;

		public x86FunctionData(Function Function)
			: base(Function)
		{
		}
	}

	struct x86TestedLocation
	{
		public x86DataLocation Location;
		public bool Succeeded;

		public x86TestedLocation(x86DataLocation Location)
		{
			this.Location = Location;
			this.Succeeded = true;
		}
	}

	struct x86TestedIdLocations
	{
		public Identifier Identifier;
		public x86TestedLocation[] Locations;
		public int Index;

		public x86TestedIdLocations(Identifier Identifier, x86TestedLocation[] Locations)
		{
			this.Identifier = Identifier;
			this.Locations = Locations;
			this.Index = -1;
		}

		public x86TestedIdLocations(Identifier Identifier, x86DataLocation[] Locations)
		{
			this.Identifier = Identifier;
			this.Index = -1;

			this.Locations = new x86TestedLocation[Locations.Length];
			for (var i = 0; i < Locations.Length; i++)
				this.Locations[i] = new x86TestedLocation(Locations[i]);
		}

		public x86DataLocation[] GetSucceededLocations()
		{
			var Ret = new List<x86DataLocation>();
			for (var i = 0; i < Locations.Length; i++)
				if (Locations[i].Succeeded) Ret.Add(Locations[i].Location);

			return Ret.ToArray();
		}
	}

	struct x86CheckedIdentifier
	{
		public Identifier Identifier;
		public x86IdentifierData Data;
		public x86DataLocation Location;
		public bool[] Written;

		public x86CheckedIdentifier(Identifier Identifier)
		{
			this.Identifier = Identifier;
			this.Data = null;
			this.Location = null;
			this.Written = null;
		}

		public x86CheckedIdentifier(Identifier Identifier, x86IdentifierData Data, x86DataLocation Location)
		{
			this.Identifier = Identifier;
			this.Data = Data;
			this.Location = Location;
			this.Written = null;
		}

		public x86CheckedIdentifier Copy()
		{
			var Ret = this;
			Ret.Written = Written.ToArray();
			return Ret;
		}
	}

	[Flags]
	enum x86CheckerFlags : byte
	{
		None = 0,
		NoBraches = 1,
		NoLoopRepetation = 2,
	}

	struct x86CheckerState
	{
		public x86CheckedIdentifier[] Identifiers;
		public int[] ReachCount;

		public x86CheckerState(x86CheckedIdentifier[] Identifiers, int[] ReachCount = null)
		{
			this.Identifiers = Identifiers;
			this.ReachCount = ReachCount;
		}

		public x86CheckerState Copy()
		{
			var Identifiers = new x86CheckedIdentifier[this.Identifiers.Length];
			for (var i = 0; i < this.Identifiers.Length; i++)
				Identifiers[i] = this.Identifiers[i].Copy();

			var ReachCount = this.ReachCount;
			if (ReachCount != null) ReachCount = ReachCount.Copy();
			return new x86CheckerState(Identifiers, ReachCount);
		}

		public void Combine(x86CheckerState State)
		{
			if (State.Identifiers.Length != Identifiers.Length)
				throw new ArgumentException("State");

			if (State.ReachCount.Length != ReachCount.Length)
				throw new ArgumentException("State");

			for (var i = 0; i < Identifiers.Length; i++)
			{
				var Arr1 = State.Identifiers[i].Written;
				var Arr2 = Identifiers[i].Written;
				if (Arr1.Length != Arr2.Length)
					throw new ArgumentException("State");

				for (var j = 0; j < Arr1.Length; j++)
					if (Arr1[j]) Arr2[j] = true;
			}
		}
	}

	sealed class x86OverwritingChecker : CodeContext
	{
		struct x86LocationExtraction
		{
			public x86DataLocation Location;
			public Identifier Identifier;

			public x86LocationExtraction(x86DataLocation Location, Identifier Identifier = null)
			{
				this.Location = Location;
				this.Identifier = Identifier;
			}
		}

		public x86Architecture Arch;
		public x86CheckerFlags CheckerFlags;
		public x86CheckerState CheckerState;
		public x86TestedIdLocations TestedLocs;

		static x86LocationExtraction ExtractLocation(ExpressionNode Node)
		{
			var Data = Node.Data.Get<x86NodeData>();
			return ExtractLocation(Data.Output);
		}

		static x86LocationExtraction ExtractLocation(x86DataLocation Location)
		{
			if (Location is x86PostCalcedLocation)
			{
				var PLoc = Location as x86PostCalcedLocation;

				if (PLoc is x86AssignVarLoc)
				{
					var AVLoc = PLoc as x86AssignVarLoc;
					var DstId = Expressions.GetIdentifier(AVLoc.Assigned);
					return new x86LocationExtraction(PLoc.Location, DstId);
				}
				else
				{
					return new x86LocationExtraction(PLoc.Location);
				}
			}

			return new x86LocationExtraction(Location);
		}

		void InitIdentifiers(x86CheckedIdentifier[] Identifiers, x86TestedIdLocations TestedLocs)
		{
			var TestedIdIndex = -1;
			for (var i = 0; i < Identifiers.Length; i++)
			{
				var Id = Identifiers[i].Identifier;
				if (Id == null || Identifiers.Where(x => x.Identifier == Id).Count() != 1)
					throw new ArgumentException();

				var Data = Id.Data.Get<x86IdentifierData>();
				if (Id == TestedLocs.Identifier) TestedIdIndex = i;

				Identifiers[i].Data = Data;
				Identifiers[i].Location = Data.Location;

				if (TestedLocs.Identifier != null)
					Identifiers[i].Written = new bool[TestedLocs.Locations.Length];
				else Identifiers[i].Written = new bool[1];
			}

			if (TestedLocs.Identifier != null)
			{
				if (TestedLocs.Index != -1)
				{
					var i = TestedLocs.Index;
					if (Identifiers[i].Identifier != TestedLocs.Identifier || Identifiers[i].Location != null)
						throw new ArgumentException();
				}
				else
				{
					if (TestedIdIndex == -1)
						throw new ArgumentException();

					TestedLocs.Index = TestedIdIndex;
				}

				for (var i = 0; i < TestedLocs.Locations.Length; i++)
					TestedLocs.Locations[i].Succeeded = true;
			}

			this.CheckerState.Identifiers = Identifiers;
			this.TestedLocs = TestedLocs;
		}

		void ConditionalAdd(x86FuncScopeData FSData, List<x86CheckedIdentifier> Identifiers, Identifier Id)
		{
			if (Id is LocalVariable)
			{
                if (!((FSData.Flags & x86FuncScopeFlags.RetAddressInParams) == 0 && Id is x86ReturnVariable))
                {
                    var IdData = Id.Data.Get<x86IdentifierData>();
                    if (IdData.Location != null)
                        Identifiers.Add(new x86CheckedIdentifier(Id));
                }
			}
		}

		x86OverwritingChecker(x86CheckerFlags Flags, IdContainer Container, x86CheckerState CheckerState, x86TestedIdLocations TestedLocs)
			: base(Container)
		{
			this.CheckerFlags = Flags;
			this.Arch = State.Arch as x86Architecture;
			this.CheckerState = CheckerState;
			this.TestedLocs = TestedLocs;
		}

		public x86OverwritingChecker(x86CheckerFlags Flags, IdContainer Container, x86TestedIdLocations TestedLocs = new x86TestedIdLocations())
			: base(Container)
		{
			var FS = Container.FunctionScope;
			var FSData = FS.Data.Get<x86FuncScopeData>();

			this.CheckerFlags = Flags;
			this.Arch = State.Arch as x86Architecture;
			if ((Flags & x86CheckerFlags.NoLoopRepetation) == 0)
				CheckerState.ReachCount = new int[FS.ContainerLocalIndexCount];

			var Identifiers = new List<x86CheckedIdentifier>();
			for (var i = 0; i < FS.LocalIdentifiers.Count; i++)
				ConditionalAdd(FSData, Identifiers, FS.LocalIdentifiers[i]);

			Identifiers.Add(new x86CheckedIdentifier(TestedLocs.Identifier));
			InitIdentifiers(Identifiers.ToArray(), TestedLocs);
		}

		public override CodeContext Copy()
		{
			return new x86OverwritingChecker(CheckerFlags, Container, CheckerState.Copy(), TestedLocs);
		}

		int GetStructIndex(string Name)
		{
			for (var i = 0; i < CheckerState.Identifiers.Length; i++)
			{
				if (CheckerState.Identifiers[i].Identifier.Name.IsEqual(Name))
					return i;
			}

			return -1;
		}

		int GetStructIndex(Identifier Id)
		{
			var Ids = CheckerState.Identifiers;
			Id = Id.RealId;

			for (var i = 0; i < Ids.Length; i++)
			{
				if (Ids[i].Identifier.RealId == Id)
					return i;
			}

			return -1;
		}

		void OnIdentifierWritten(Identifier Id)
		{
			var IdData = Id.Data.Get<x86IdentifierData>();
			var Index = GetStructIndex(Id);

			if (Index != -1)
			{
				if (TestedLocs.Identifier != null && TestedLocs.Index == Index)
				{
					for (var i = 0; i < TestedLocs.Locations.Length; i++)
					{
						var DstLoc = TestedLocs.Locations[i].Location;
						for (var j = 0; j < CheckerState.Identifiers.Length; j++)
						{
							var IdjLoc = CheckerState.Identifiers[j].Location;
							if (Index != j && DstLoc.Compare(IdjLoc, x86OverlappingMode.Partial))
								CheckerState.Identifiers[j].Written[i] = true;
						}
					}
				}
				else
				{
					OnLocationWritten(IdData.Location);
				}

				for (var j = 0; j < CheckerState.Identifiers[Index].Written.Length; j++)
					CheckerState.Identifiers[Index].Written[j] = false;
			}
			else if (IdData.Location != null)
			{
				OnLocationWritten(IdData.Location);
			}
		}

		bool HasSucceededLocation()
		{
			if (TestedLocs.Identifier == null)
				throw new InvalidOperationException();

			for (var i = 0; i < TestedLocs.Locations.Length; i++)
				if (TestedLocs.Locations[i].Succeeded) return true;

			return false;
		}

		bool OnIdentifierRead(Identifier Id)
		{
			var Index = GetStructIndex(Id);
			if (Index != -1)
			{
				if (TestedLocs.Identifier != null)
				{
					for (var i = 0; i < TestedLocs.Locations.Length; i++)
					{
						if (CheckerState.Identifiers[Index].Written[i])
							TestedLocs.Locations[i].Succeeded = false;
					}

					if (!HasSucceededLocation())
						return false;
				}
				else
				{
					return !CheckerState.Identifiers[Index].Written[0];
				}
			}

			return true;
		}

		void OnGRegLocationWritten(int Index, x86RegisterMask Mask)
		{
			OnLocationWritten(x =>
				!x86DataLocations.Check(x, y =>
				{
					var Gy = y as x86GRegLocation;
					return Gy == null || Gy.Index != Index || Gy.Mask.IsFree(Mask);
				})
			);
		}

		bool DisableLocation(x86DataList List)
		{
			return DisableLocation(x => !List.IsFree(x));
		}

		bool DisableLocation(x86DataLocation Location)
		{
			if (Location == null) throw new ArgumentNullException("Location");
			return DisableLocation(x => x.Compare(Location, x86OverlappingMode.Partial));
		}

		bool DisableGRegLocation(int Index, x86RegisterMask Mask)
        {
            return DisableLocation(x => 
				!x86DataLocations.Check(x, y =>
				{
					var Gy = y as x86GRegLocation;
					return Gy == null || Gy.Index != Index || Gy.Mask.IsFree(Mask);
				})
			);
        }

        bool DisableLocation(Predicate<x86DataLocation> Func)
        {
            for (var i = 0; i < CheckerState.Identifiers.Length; i++)
                if (TestedLocs.Identifier != null)
                {
                    if (TestedLocs.Index == i)
                    {
                        for (var j = 0; j < TestedLocs.Locations.Length; j++)
                        {
                            if (Func(TestedLocs.Locations[j].Location))
                                TestedLocs.Locations[j].Succeeded = false;
                        }

                        if (!HasSucceededLocation())
                            return false;
                    }
                    else
                    {
                        if (Func(CheckerState.Identifiers[i].Location))
                            return false;
                    }

                }
                else if (!CheckerState.Identifiers[i].Written[0])
                {
                    if (Func(CheckerState.Identifiers[i].Location))
                        return false;
                }

            return true;
        }

		void OnLocationWritten(Predicate<x86DataLocation> Func)
		{
			for (var i = 0; i < CheckerState.Identifiers.Length; i++)
				if (TestedLocs.Identifier != null)
				{
					if (TestedLocs.Index == i)
					{
						for (var j = 0; j < TestedLocs.Locations.Length; j++)
							if (!CheckerState.Identifiers[i].Written[j] && TestedLocs.Locations[j].Succeeded)
							{
								if (Func(TestedLocs.Locations[j].Location))
									CheckerState.Identifiers[i].Written[j] = true;
							}
					}
					else if (Func(CheckerState.Identifiers[i].Location))
					{
						for (var j = 0; j < TestedLocs.Locations.Length; j++)
							CheckerState.Identifiers[i].Written[j] = true;
					}
				}
				else if (!CheckerState.Identifiers[i].Written[0])
				{
					if (Func(CheckerState.Identifiers[i].Location))
						CheckerState.Identifiers[i].Written[0] = true;
				}
		}

		void OnLocationWritten(x86DataLocation Location)
		{
			if (Location == null) throw new ArgumentNullException("Location");
			OnLocationWritten(x => x.Compare(Location, x86OverlappingMode.Partial));
		}

		void OnLocationWritten(x86DataList List)
		{
			OnLocationWritten(x => !List.IsFree(x));
		}

		void OnLocationWritten(x86TemporaryData TempData)
		{
			if (TempData.GRegs != null)
			{
				for (var i = 0; i < TempData.GRegs.Length; i++)
					OnLocationWritten(TempData.GRegs[i].Location);
			}

			if (TempData.SSERegs != null)
			{
				for (var i = 0; i < TempData.SSERegs.Length; i++)
					OnLocationWritten(TempData.SSERegs[i]);
			}

			if (TempData.Memory != null)
				OnLocationWritten(TempData.Memory);
		}

		bool CheckSaveChResults(ExpressionNode Node, x86NodeData Data)
		{
			if ((Data.Flags & x86NodeFlags.SaveChResults) == 0)
				return true;

			var Ch = Node.Children;
			for (var i = 0; i < Ch.Length; i++)
			{
				var Loci = ExtractLocation(Ch[i]);
				if (Loci.Identifier == null) continue;

				var Index = GetStructIndex(Loci.Identifier);
				if (Index == -1) continue;

				if (TestedLocs.Identifier != null && TestedLocs.Index == Index)
				{
					for (var LocIndex = 0; LocIndex < TestedLocs.Locations.Length; LocIndex++)
					{
						if (!TestedLocs.Locations[LocIndex].Succeeded) continue;

						var CurrIdLoc = TestedLocs.Locations[LocIndex].Location;
						for (var j = 0; j < Ch.Length; j++)
						{
							if (i == j) continue;

							x86DataLocCalcHelper.ForeachIndexMemberNodeAndChildren(Ch[j], x =>
							{
								var Locx = ExtractLocation(x);
								if (Locx.Location == null) return;

								if (CurrIdLoc.Compare(Locx.Location, x86OverlappingMode.Partial))
									TestedLocs.Locations[LocIndex].Succeeded = false;
							});
						}
					}
				}
				else if (Loci.Location != null)
				{
					for (var j = 0; j < Ch.Length; j++)
					{
						if (i == j) continue;

						var Failed = false;
						x86DataLocCalcHelper.ForeachIndexMemberNodeAndChildren(Ch[j], x =>
						{
							var Locx = ExtractLocation(x);
							if (Locx.Location == null) return;

							if (Loci.Location.Compare(Locx.Location, x86OverlappingMode.Partial))
								Failed = true;
						});

						if (Failed)
							return false;
					}
				}
			}

			return HasSucceededLocation();
		}

		public bool IsOverwritten(ExpressionNode Node, x86DataLocation MoveAndOpPos = null)
		{
			var Data = Node.Data.Get<x86NodeData>();
			var Calculated = false;

			for (var i = 0; i < Node.LinkedNodes.Count; i++)
			{
				var LNode = Node.LinkedNodes[i];
				if ((LNode.Flags & LinkedNodeFlags.PostComputation) != 0)
					continue;

				var LData = LNode.Data.Get<x86LinkedNodeData>();
				if (IsOverwritten(LNode.Node, LData.Location))
					return true;

				if ((LData.Flags & x86LinkedNodeFlags.AllocateData) != 0)
					OnLocationWritten(LData.Location);
			}

			if ((Data.Flags & x86NodeFlags.IndexMemberNode) == 0)
			{
				OnLocationWritten(Data.TempData);
				if (Node.Children != null)
				{
					for (var i = 0; i < Node.Children.Length; i++)
						x86DataLocCalcHelper.ForeachIndexMemberNode(Node.Children[i], x =>
						{
							var xData = x.Data.Get<x86NodeData>();
							OnLocationWritten(xData.TempData);
						});
				}
			}

			if (Node is IdExpressionNode)
			{
				var IdNode = Node as IdExpressionNode;
				if (!OnIdentifierRead(IdNode.Identifier)) return true;
			}
			else if (Node is OpExpressionNode)
			{
				var OpNode = Node as OpExpressionNode;
				var Op = OpNode.Operator;
				var Ch = OpNode.Children;

				if (!CheckSaveChResults(Node, Data))
					return true;
				
				if (Op == Operator.Assignment)
				{
					Calculated = true;
					var Dst = x86Expressions.GetLocation(Arch, Ch[0]) as x86MemoryLocation;
					var Ch0Data = Ch[0].Data.Get<x86NodeData>();
					var DstIsSimpleId = Ch[0] is IdExpressionNode &&
						(Ch0Data.Flags & x86NodeFlags.IdentifierByRef) == 0;

					if (!DstIsSimpleId && IsOverwritten(Ch[0])) return true;
					if (IsOverwritten(Ch[1], Dst)) return true;

					if (DstIsSimpleId)
					{
						var IdCh0 = Ch[0] as IdExpressionNode;
						OnIdentifierWritten(IdCh0.Identifier);
					}
					else if ((Ch0Data.Flags & x86NodeFlags.IndexMemberNode) != 0)
					{
						var Result = false;
						x86DataLocCalcHelper.ForeachIndexMemberNode(Ch[0], x =>
						{
							var Idx = x as IdExpressionNode;
							if (Idx != null && !OnIdentifierRead(Idx.Identifier)) Result = true;
						});

						if (Result)
							return true;
					}
				}
				else if (Op == Operator.Cast || Op == Operator.Reinterpret)
				{
					Calculated = true;
					var Pos = x86Expressions.GetLocation(Arch, Node);
					if (IsOverwritten(Ch[0], Pos as x86MemoryLocation)) return true;
				}
				else if (Op == Operator.Call || Op == Operator.NewObject)
				{
					Calculated = true;
					var FuncType = Ch[0].Type as TypeOfFunction;
					var CallConv = FuncType.CallConv;
					var x86CallConv = Arch.GetCallingConvention(CallConv);
					var ParameterSequence = x86CallConv.ParameterSequence;
					var DS = new x86DataSequence(Arch, ParameterSequence);

					var RetType = FuncType.RetType.RealId;
					if ((RetType is StructType || RetType is NonrefArrayType) && DS.CanAllocGReg())
						OnGRegLocationWritten(DS.GetGRegisterIndex(), Arch.RegisterMask);

					if (IsOverwritten(Ch[0]))
						return true;

					if (x86Expressions.NeedSelfParameter(Node) && DS.CanAllocGReg())
						OnGRegLocationWritten(DS.GetGRegisterIndex(), Arch.RegisterMask);

					var Types = FuncType.GetTypes();
					var RegList = new x86DataLocation[Ch.Length];
					Arch.ProcessRegisterParams(Types, CallConv, (i, Pos) => RegList[i + 1] = Pos, DS);

					for (var i = 1; i < Ch.Length; i++)
						if (RegList[i] == null && IsOverwritten(Ch[i])) return true;

					for (var i = 1; i < Ch.Length; i++)
					{
						if (RegList[i] == null) continue;
						if (IsOverwritten(Ch[i], RegList[i])) return true;
						OnLocationWritten(RegList[i]);
					}

					if (IsOverwritten(Ch[0])) return true;
				}
			}

			if (!Calculated && Node.Children != null)
			{
				for (var i = 0; i < Node.Children.Length; i++)
					if (IsOverwritten(Node.Children[i])) return true;
			}

			if (Data.Output != null)
			{
				/*
				if (Data.Output is x86AssignVarLoc)
				{
					var AVLoc = Data.Output as x86AssignVarLoc;
					var IdNode = AVLoc.Assigned as IdExpressionNode;
					if (IsIdentifierOverwritten(IdNode.Id)) return true;
				}
			  * 
				var Extracted = Data.ExtractedOutput;
				if (Extracted != null) OnLocationWritten(Extracted);
				*/

				var Extracted = ExtractLocation(Data.Output);
				if (TestedLocs.Identifier != null && Extracted.Identifier != null &&
					Extracted.Identifier.IsEquivalent(TestedLocs.Identifier))
				{
					for (var LocIndex = 0; LocIndex < TestedLocs.Locations.Length; LocIndex++)
					{
						for (var i = 0; i < CheckerState.Identifiers.Length; i++)
							if (i != TestedLocs.Index && !CheckerState.Identifiers[i].Written[LocIndex])
							{
								var DestLoc = TestedLocs.Locations[LocIndex].Location;
								if (DestLoc.Compare(CheckerState.Identifiers[i].Location, x86OverlappingMode.Partial))
									CheckerState.Identifiers[i].Written[LocIndex] = true;
							}
					}
				}
				else if (Extracted.Location != null)
				{
					OnLocationWritten(Extracted.Location);
				}
			}

			if (Data.UsedDataBySelf != null) OnLocationWritten(Data.UsedDataBySelf);

			for (var i = 0; i < Node.LinkedNodes.Count; i++)
			{
				var LNode = Node.LinkedNodes[i];
				if ((LNode.Flags & LinkedNodeFlags.PostComputation) != 0)
				{
					if (IsOverwritten(LNode.Node)) return true;
				}
			}

			return false;
		}

		public override OnEnterLeaveResult OnEnterContainer()
		{
			if (Container is Command)
			{
				var Comm = Container as Command;
				if (Comm.Type == CommandType.If)
				{
					var RetValue = OnEnterLeaveResult.Succeeded;
					if ((CheckerFlags & x86CheckerFlags.NoBraches) == 0)
					{
						for (var i = 0; i < Comm.Children.Count; i++)
						{
							var Chi = Comm.Children[i];
							if (i < Comm.Expressions.Count)
							{
								if (IsOverwritten(Comm.Expressions[i]))
									RetValue |= OnEnterLeaveResult.FailedAndCancel;
								else if ((Copy(Chi).Process() & CodeContextResult.Failed) != 0)
									RetValue |= OnEnterLeaveResult.FailedAndCancel;
							}
							else
							{
								if ((Copy(Chi).Process() & CodeContextResult.Failed) != 0)
									RetValue |= OnEnterLeaveResult.Failed;

								RetValue |= OnEnterLeaveResult.Cancel;
							}
						}
					}
					else
					{
						var NewStates = new List<x86CheckerState>();
						for (var i = 0; i < Comm.Children.Count; i++)
						{
							if (i < Comm.Expressions.Count)
							{
								if (IsOverwritten(Comm.Expressions[i]))
									RetValue |= OnEnterLeaveResult.FailedAndCancel;
							}

							var OldState = CheckerState;
							CheckerState = CheckerState.Copy();

							if ((Process(Comm.Children[i]) & CodeContextResult.Failed) != 0)
								RetValue |= OnEnterLeaveResult.FailedAndCancel;

							NewStates.Add(CheckerState);
							CheckerState = OldState;
						}

						NewStates.ForEach(x => CheckerState.Combine(x));
					}

					return RetValue;
				}
                else if (Commands.IsLoopCommand(Comm.Type))
                {
                    if (Comm.Type == CommandType.For)
                    {
                        if (IsOverwritten(Comm.Expressions[0]))
                            return OnEnterLeaveResult.FailedAndCancel;

                        if (IsOverwritten(Comm.Expressions[1]))
                            return OnEnterLeaveResult.FailedAndCancel;
                    }
                    else if (Comm.Type == CommandType.While)
                    {
                        if (IsOverwritten(Comm.Expressions[0]))
                            return OnEnterLeaveResult.FailedAndCancel;
                    }

                    if (Comm.WillRun == ConditionResult.Unknown && (CheckerFlags & x86CheckerFlags.NoBraches) != 0)
                    {
                        var RetValue = OnEnterLeaveResult.Succeeded;
                        var OldState = CheckerState;
                        CheckerState = CheckerState.Copy();

                        if ((Process(Comm.Children[0]) & CodeContextResult.Failed) != 0)
                            RetValue |= OnEnterLeaveResult.FailedAndCancel;

                        OldState.Combine(CheckerState);
                        CheckerState = OldState;
                        return RetValue;
                    }
                }
                else if (Comm.Type == CommandType.Expression)
                {
                    if (IsOverwritten(Comm.Expressions[0]))
                        return OnEnterLeaveResult.FailedAndCancel;
                }
                else if (Comm.Type == CommandType.Return)
                {
                    if (Comm.Expressions != null && Comm.Expressions.Count > 0)
                    {
                        if (IsOverwritten(Comm.Expressions[0]))
                            return OnEnterLeaveResult.FailedAndCancel;
                    }
                }
                else if (Commands.IsJumpCommand(Comm.Type))
                {
                    var DstContainer = Comm.GetJumpDestination().Container;
                    for (var i = 0; i < CheckerState.Identifiers.Length; i++)
                    {
                        var IdContainer = CheckerState.Identifiers[i].Identifier.Container;
                        if (DstContainer != IdContainer && !DstContainer.IsSubContainerOf(IdContainer))
                            continue;

                        if (TestedLocs.Identifier != null)
                        {
                            for (var Loc = 0; Loc < TestedLocs.Locations.Length; Loc++)
                            {
                                if (CheckerState.Identifiers[i].Written[Loc])
                                    TestedLocs.Locations[Loc].Succeeded = false;
                            }
                        }
                        else if (CheckerState.Identifiers[i].Written[0])
                        {
                            return OnEnterLeaveResult.FailedAndCancel;
                        }
                    }

                    if (!HasSucceededLocation())
                        return OnEnterLeaveResult.FailedAndCancel;
                }
                else if (Comm.Type == CommandType.Throw || Comm.Type == CommandType.Rethrow)
                {
                    if (IsOverwritten(Comm.Expressions[0]))
                        return OnEnterLeaveResult.FailedAndCancel;
                }
			}

			else if (Container is CodeScopeNode)
			{
				if (Container is FunctionScope)
				{
                    var FS = Container as FunctionScope;
                    var FSData = Container.Data.Get<x86FuncScopeData>();
					if (!DisableLocation(FSData.DisabledLocations))
						return OnEnterLeaveResult.FailedAndCancel;

					if (!CheckParameters(FS))
						return OnEnterLeaveResult.FailedAndCancel;
				}

				var Scope = Container as CodeScopeNode;
				var ParentComm = Scope.Parent as Command;

				if (ParentComm != null && ParentComm.Type == CommandType.Try)
				{
					if (ParentComm.FinallyScope == Scope || ParentComm.CatchScope == Scope)
					{
						var AsCall = Arch.CallingConventions.BirdCall;
						OnLocationWritten(x => !AsCall.IsSavedRegister(x));
					}
				}

			}

			return base.OnEnterContainer();
		}

		bool CheckParameters(FunctionScope FS)
		{
			var FSData = FS.Data.Get<x86FuncScopeData>();
			for (var i = 0; i < FSData.AllParams.Count; i++)
			{
				var Id = FSData.AllParams[i];
				var IdData = Id.Data.Get<x86IdentifierData>();

				if (TestedLocs.Identifier.IsEquivalent(Id))
				{
					for (var LocIndex = 0; LocIndex < TestedLocs.Locations.Length; LocIndex++)
					{
						var Loc = TestedLocs.Locations[LocIndex].Location;
						for (var j = i + 1; j < FSData.AllParams.Count; j++)
						{
							var jIdData = FSData.AllParams[j].Data.Get<x86IdentifierData>();
							if (jIdData.ParamLocation.Compare(Loc, x86OverlappingMode.Partial))
								TestedLocs.Locations[LocIndex].Succeeded = false;
						}
					}

					if (!HasSucceededLocation())
						return false;
				}
				else if (IdData.Location != null && !IdData.ParamLocation.Compare(IdData.Location))
				{
					for (var j = i + 1; j < FSData.AllParams.Count; j++)
					{
						var jIdData = FSData.AllParams[j].Data.Get<x86IdentifierData>();
						if (jIdData.ParamLocation.Compare(IdData.Location, x86OverlappingMode.Partial))
							return false;
					}
				}

				OnIdentifierWritten(Id);
			}

			return true;
		}

		public override OnEnterLeaveResult OnLeaveContainer()
		{
			if (Container.Parent is Command)
			{
				var Comm = Container.Parent as Command;
				if (Comm.Type == CommandType.For)
				{
					if (IsOverwritten(Comm.Expressions[2]))
						return OnEnterLeaveResult.FailedAndCancel;

					if (IsOverwritten(Comm.Expressions[1]))
						return OnEnterLeaveResult.FailedAndCancel;
				}
				else if (Comm.Type == CommandType.DoWhile)
				{
					if (IsOverwritten(Comm.Expressions[0]))
						return OnEnterLeaveResult.FailedAndCancel;
				}

				if ((CheckerFlags & x86CheckerFlags.NoLoopRepetation) == 0)
				{
					if (Commands.IsLoopCommand(Comm.Type))
					{
						CheckerState.ReachCount[Comm.LocalIndex]++;
						if (CheckerState.ReachCount[Comm.LocalIndex] < 2)
							return OnEnterLeaveResult.EnterNew;
					}
				}
			}

			return base.OnLeaveContainer();
		}
	}

	public class x86VariableLocCalcer
	{
		public x86Architecture Arch;
		public x86DataAllocator TempAllocator;
		public List<LocalVariable> List;

		void GetAllIdentifiers(IdContainer Container)
		{
			for (var i = 0; i < Container.IdentifierList.Count; i++)
			{
				var Id = Container.IdentifierList[i] as LocalVariable;
				if (Id != null) List.Add(Id);
			}

			for (var i = 0; i < Container.Children.Count; i++)
				GetAllIdentifiers(Container.Children[i]);
		}

		int GetIdPriority(Identifier Id)
		{
			var IdData = Id.Data.Get<x86IdentifierData>();
			var Ret = IdData.ReferenceCount;

			if (x86Architecture.IsPointerType(Id.TypeOfSelf))
			{
				if (Ret < (int.MaxValue >> 1)) Ret <<= 1;
				else Ret = int.MaxValue;
			}

			return Ret;
		}

		void ConstructAllocationList(IdContainer Container)
		{
			List = new List<LocalVariable>();
			GetAllIdentifiers(Container);

			List.Sort((x, y) =>
			{
				var xPriority = GetIdPriority(x);
				var yPriority = GetIdPriority(y);

				if (xPriority > yPriority) return -1;
				else if (xPriority < yPriority) return 1;
				else return 0;
			});
		}

		public x86VariableLocCalcer(x86Architecture Arch)
		{
			this.Arch = Arch;
		}

		public void Calc(IdContainer Container)
		{
			ConstructAllocationList(Container);
			TempAllocator = new x86DataAllocator(Container);
			//DoAllocations(RootList, Container, UseExistingLocs);
			//DoAllocations(Container, AllocatePointers);
			//DoAllocations(Container, AllocateBytes);
			DoAllocations(Container, AllocateRemaining);
		}

		private void AllocateRemaining(LocalVariable Id, x86IdentifierData IdData)
		{
			if (IdData.Location == null) 
				AllocateVariable(Id, IdData);
		}

		private void AllocateBytes(LocalVariable Id, x86IdentifierData IdData)
		{
            var Type = Id.TypeOfSelf.RealId as Type;
            if (IdData.Location == null && Type.Size == 1)
				AllocateVariable(Id, IdData);
		}

		private void AllocatePointers(LocalVariable Id, x86IdentifierData IdData)
		{
			if (IdData.Location == null && x86Architecture.IsPointerType(Id.TypeOfSelf))
				AllocateVariable(Id, IdData);
		}

		private void AllocateVariable(LocalVariable Id, x86IdentifierData IdData)
		{
			var State = Id.Container.State;
			if ((State.Flags & CompilerStateFlags.DebugMode) == 0)
				x86Functions.GetRegisterForVariable(Id);

			if (IdData.Location == null)
			{
				var T = Id.TypeOfSelf.RealId as Type;
				var DataLocType = x86Identifiers.GetPossibleLocations(Id, IdData);

				PrepareTempAllocator(Id, IdData);
				IdData.Location = TempAllocator.Allocate(T.Size, T.Align, DataLocType, IdData.LocationCantBe);
			}

			SetUsedInParents(Id.Container, IdData.Location);
			IdData.SetLocationUsed(true);
			IdData.CheckLocation();
		}

		private void SetUsedInParents(IdContainer Container, x86DataLocation Location)
		{
			Container.ForEachParent<IdContainer>(x =>
			{
				var xData = x.Data.Get<x86IdContainerData>();
				xData.Allocator.SetUsed(Location);
			}, Container.FunctionScope.Parent);
		}

		private void PrepareTempAllocator(LocalVariable Id, x86IdentifierData IdData)
		{
			int Start, End;
			IdData.GetStartEnd(out Start, out End);
			TempAllocator.Reset();
			
			var ContainerData = Id.Container.Data.Get<x86IdContainerData>();
			TempAllocator.SetUsed(ContainerData.Allocator);
			/*
			if (Id.Container is Command)
			{
				var Comm = Id.Container as Command;
				if (Comm.Expressions != null)
				{
					for (var i = 0; i < Comm.Expressions.Count; i++)
					{
						var Node = Comm.Expressions[i];
						var Data = Node.Data.Get<x86NodeData>();
						TempAllocator.SetUsed(Data.AllAllocated);
					}
				}
			}
			*/
			for (var i = Start; i <= End; i++)
			{
				var Ch = Id.Container.Children[i];
				var ChData = Ch.Data.Get<x86IdContainerData>();
				TempAllocator.SetUsed(ChData.Allocator);
			}
		}

		private void DoAllocations(IdContainer Container, Action<LocalVariable, x86IdentifierData> Action)
		{
			for (var i = 0; i < List.Count; i++)
			{
				var IdData = List[i].Data.Get<x86IdentifierData>();
				Action(List[i], IdData);
			}
		}
	}

	public static class x86Functions
	{
		public static bool ProcessContainer(IdContainer Container)
		{
			var FS = Container.FunctionScope;
			var FSData = FS.Data.Get<x86FuncScopeData>();
			var Data = Container.Data.GetOrCreate<x86IdContainerData>(Container);

			if (Container is Command)
			{
				var Command = Container as Command;
				if (!ProcessCommand(Command)) return false;
			}

			for (var i = 0; i < Container.IdentifierList.Count; i++)
			{
				var Id = Container.IdentifierList[i] as LocalVariable;
				if (Id != null)
				{
					if (!Id.Data.Contains<x86IdentifierData>())
						Id.Data.Create<x86IdentifierData>(Id);

					var Type = Id.TypeOfSelf.RealId as Type;
					FSData.StackAlignment = Math.Max(FSData.StackAlignment, Type.Align);
				}
			}

			return true;
		}

		public static bool ProcessCommand(Command Command)
		{
			if (Command.Type == CommandType.Return)
			{
				var FScope = Command.FunctionScope;
				var FSData = FScope.Data.Get<x86FuncScopeData>();
				if (Command.Expressions != null && Command.Expressions.Count > 0)
				{
					var Node = Command.Expressions[0];
					var Plugin = Command.GetPlugin();
					if (!Plugin.Begin()) return false;

					Node = Expressions.SetValue(FSData.ReturnVariable, Node, Plugin, Command.Code, true);
					if (Node == null) return false;

					Command.Expressions[0] = Node;
				}
			}

			return true;
		}

		public static bool ProcessFunction(FunctionScope Scope)
		{
			var Arch = Scope.State.Arch as x86Architecture;
			var Data = new x86FuncScopeData(Scope);
			Data.Expressions = new List<ExpressionNode>(64);
			Scope.Data.Set(Data);

			InitFunction(Scope);
			CalcParamDataLoc(Scope);
			return NCProcessor.ProcessCode(Scope);
		}

		static void MakeRefType(Variable Var)
		{
			var Type = Var.TypeOfSelf.RealId as Type;
			if ((Type.TypeFlags & TypeFlags.ReferenceValue) == 0)
				Type = new ReferenceType(Var.Container, Var.TypeOfSelf, ReferenceMode.Unsafe);

			Var.Children[0] = Type;
		}

		static void InitFunction(FunctionScope Scope)
		{
			var Arch = Scope.State.Arch as x86Architecture;
			var FuncType = Scope.Type;
			var RetType = FuncType.RetType.RealId as Type;
			if (RetType is EnumType) RetType = (RetType as EnumType).TypeOfValues;

			var Data = Scope.Data.Get<x86FuncScopeData>();
			Data.AllParams = Scope.Parameters.Change<LocalVariable>();
			Data.DisabledLocations = new x86DataList(Arch);
			Data.StackPointer = new x86GRegLocation(Arch, 4, Arch.RegisterMask);
			Data.DisabledLocations.SetUsed(Data.StackPointer);

			x86ReturnVariable RetVar = null;
			if (!(FuncType.RetType.RealId is VoidType))
			{
				RetVar = new x86ReturnVariable(Scope, new CodeString(), FuncType.RetType);
				RetVar.LocalIndex = Scope.LocalIdentifiers.Count;
				Scope.LocalIdentifiers.Add(RetVar);
				Data.ReturnVariable = RetVar;
			}

			if (RetType is StructType || RetType is NonrefArrayType)
			{
				Data.Flags |= x86FuncScopeFlags.RetAddressInParams;
				MakeRefType(RetVar);
				RetVar.Data.Set(new x86IdentifierData(RetVar));
				RetVar.PreAssigned = true;
			}
			else
			{
				if (RetType is NonFloatType || RetType is PointerType || RetType is BooleanType ||
					RetType is ReferenceType || RetType is ClassType || RetType is EnumType ||
					RetType is CharType || RetType is StringType || RetType is ObjectType || RetType is RefArrayType)
				{
					var Size = RetType.Size;
					var RetVarData = new x86IdentifierData(RetVar);

					if (Size > Arch.RegSize)
					{
						if (Size == 2 * Arch.RegSize) 
							RetVarData.Location = new x86MultiLocation(Arch, 0, 2);
						else throw new NotImplementedException();
					}
					else
					{
						if (FuncType.CallConv == CallingConvention.BirdCall)
							RetVarData.Location = new x86GRegLocation(Arch, 0, RetType.Size);
						else RetVarData.Location = new x86GRegLocation(Arch, 0, Arch.RegSize);
					}

					RetVar.Data.Set(RetVarData);
				}
				else if (RetType is FloatType)
				{
					var IdData = new x86IdentifierData(RetVar);
					if (Arch.FloatingPointMode == x86FloatingPointMode.SSE)
						IdData.Location = new x86SSERegLocation(Arch, 0);
					else if (Arch.FloatingPointMode != x86FloatingPointMode.FPU)
						throw new NotImplementedException();

					RetVar.Data.Set(IdData);
				}
				else if (!(RetType is VoidType))
				{
					throw new ApplicationException();
				}
			}

			if (Scope.SelfVariable != null)
			{
				MakeRefType(Scope.SelfVariable);
				Data.AllParams.Insert(0, Scope.SelfVariable);
				Scope.SelfVariable.Data.Set(new x86IdentifierData(Scope.SelfVariable));

				if (Scope.BaseVariable != null)
				{
					MakeRefType(Scope.BaseVariable);
					Scope.BaseVariable.Data.Set(new x86IdentifierData(Scope.BaseVariable));
				}
			}

			if (RetType is StructType)
				Data.AllParams.Insert(0, RetVar);

			for (var i = 0; i < Scope.Parameters.Count; i++)
			{
				var Param = Scope.Parameters[i];
				Param.Data.Set(new x86IdentifierData(Param));
			}
		}

		static void UpdateParamBaseRegisters(FunctionScope Scope)
		{
			var FSData = Scope.Data.Get<x86FuncScopeData>();
			for (var i = 0; i < FSData.AllParams.Count; i++)
			{
				var Param = FSData.AllParams[i];
				var ParamData = Param.Data.Get<x86IdentifierData>();
				var Loc = ParamData.ParamLocation as x86StackLocation;
				if (Loc != null) Loc.UpdateBaseRegister();
			}
		}

		static void Reset(FunctionScope Scope)
		{
			var FSData = Scope.Data.Get<x86FuncScopeData>();
			FSData.DisabledLocations.Reset();

			for (var i = 0; i < FSData.AllParams.Count; i++)
			{
				var Param = FSData.AllParams[i];
				var ParamData = Param.Data.Get<x86IdentifierData>();
				ParamData.Reset();
			}

			Reset((IdContainer)Scope);
		}

		static void Reset(IdContainer Container)
		{
			Container.Data.Get<x86IdContainerData>().Reset();
			for (var i = 0; i < Container.IdentifierList.Count; i++)
			{
				var Id = Container.IdentifierList[i] as LocalVariable;
				if (Id != null) Id.Data.Get<x86IdentifierData>().Reset();
			}

			for (var i = 0; i < Container.Children.Count; i++)
				Reset(Container.Children[i]);
		}

		static int GetNeededSpaceForSaving(FunctionScope Scope, x86DataAllocator Allocator)
		{
			var Ret = 0;
			var Arch = Allocator.Arch;
			var SSERegSize = Arch.SSERegSize;
			var Conv = Scope.Type.CallConv;
			var x86CallConv = Arch.GetCallingConvention(Conv);

			for (var i = 0; i < Allocator.SSERegisters.Size; i++)
			{
				if (Allocator.SSERegisters[i] && x86CallConv.SavedSSERegs.Contains(i))
					Ret += SSERegSize;
			}

			return Ret;
		}

		public static void CreateAssembly(FunctionScope FS)
		{
			var State = FS.State;
			var Arch = State.Arch as x86Architecture;
			var FSData = FS.Data.Get<x86FuncScopeData>();
			var FuncData = FS.Function.Data.Get<x86FunctionData>();
			var x86CallConv = Arch.GetCallingConvention(FS.Type.CallConv);

			var OldFSFlags = FSData.Flags;
			if (FSData.StackAlignment > Arch.RegSize)
				FSData.Flags |= x86FuncScopeFlags.SaveParameterPointer;

			var CG = new x86CodeGenerator(FS);
			var ToCopy = CalcLocations(FS);
			var Allocator = FSData.Allocator;

			var NeededSpaceForSaving = GetNeededSpaceForSaving(FS, Allocator);
			if (NeededSpaceForSaving == 0) FSData.SpaceForSaving = null;
			else FSData.SpaceForSaving = Allocator.AllocMemory(NeededSpaceForSaving, Arch.SSERegSize);

			if (Allocator.StackOffset == 0 && (FSData.Flags & x86FuncScopeFlags.FunctionCalled) == 0)
			{
				FSData.StackAlignment = x86CallConv.StackAlignment;

				if (FSData.StackAlignment <= Arch.RegSize &&
					(OldFSFlags & x86FuncScopeFlags.SaveParameterPointer) == 0)
				{
					FSData.Flags = OldFSFlags;
					UpdateParamBaseRegisters(FS);
				}
			}

			CG.BeginFunction(FS, Allocator);
			if (ToCopy != null)	CG.MoveData(ToCopy);

			FS.GetAssembly(CG);
			if (FSData.FuncLeaveInsCount < 4)
			{
				Action Func = () => CG.LeaveFunction(FS, Allocator);
				var InsContainer = CG.SetJumpReplacing(FS.ReturnLabel, Func);
				CG.InsContainer.Add(InsContainer);
			}
			else
			{
				CG.LeaveFunction(FS, Allocator);
			}

			CG.Optimize();

			var InsEncoder = new x86InstructionEncoder();
			FuncData.Assembly = CG.InsContainer.EncodeToText(InsEncoder);
		}

		static void CalcExprRegs(List<ExpressionNode> Expressions, x86DataLocCalcer DataLocCalcer)
		{
			for (var i = 0; i < Expressions.Count; i++)
				DataLocCalcer.Calc(Expressions[i]);
		}

		static bool CheckMem2Mem(List<ExpressionNode> Expressions, x86DataLocChecker DataLocChecker)
		{
			for (var i = 0; i < Expressions.Count; i++)
			{
				if (!DataLocChecker.Check(Expressions[i]))
					return false;
			}

			return true;
		}

		static void CalcStackPointers(FunctionScope FS)
		{
			var Arch = FS.State.Arch as x86Architecture;
			var FSData = FS.Data.Get<x86FuncScopeData>();

			//FSData.Flags |= x86FuncScopeFlags.SaveFramePointer;
			//FSData.Flags |= x86FuncScopeFlags.SaveParameterPointer;
			//FSData.StackAlignment = 16;

			if ((FSData.Flags & x86FuncScopeFlags.SaveFramePointer) != 0)
			{
				FSData.FramePointer = new x86GRegLocation(Arch, 5, Arch.RegisterMask);
				FSData.DisabledLocations.SetUsed(FSData.FramePointer);
			}

			if ((FSData.Flags & x86FuncScopeFlags.SaveParameterPointer) != 0)
			{
				FSData.ParameterPointer = new x86GRegLocation(Arch, 3, Arch.RegisterMask);
				FSData.DisabledLocations.SetUsed(FSData.ParameterPointer);
			}
		}

		static private List<x86MoveStruct> CalcLocations(FunctionScope FS)
		{
			var Arch = FS.State.Arch as x86Architecture;
			var FSData = FS.Data.Get<x86FuncScopeData>();
			var Params = FSData.AllParams;
			var Expressions = FSData.Expressions;

			var VarLocCalcer = new x86VariableLocCalcer(Arch);
			var DataLocCalcer = new x86DataLocCalcer(Arch);
			var DataLocChecker = new x86DataLocChecker(Arch);
			var ToCopy = new List<x86MoveStruct>();
			var ReCalc = false;
			var CalcCount = 0;

			do
			{
				ReCalc = false;
				Reset(FS);
				CalcStackPointers(FS);
				UpdateParamBaseRegisters(FS);

				if (Params.Count > 0)
				{
					ToCopy.Clear();
					for (var i = 0; i < Params.Count; i++)
					{
						var ParamData = Params[i].Data.Get<x86IdentifierData>();
						if ((ParamData.Flags & x86IdentifierFlags.ParamLocUsable) == 0)
							ParamData.SetParameterUsed();
					}
				}

				CalcExprRegs(Expressions, DataLocCalcer);
				VarLocCalcer.Calc(FS);

				if (Params.Count > 0)
				{
					for (var i = 0; i < Params.Count; i++)
						ProcessParam(Params[i], ToCopy);
				}

                if (FSData.Allocator.StackOffset > 0)
                {
                    if ((FSData.Flags & x86FuncScopeFlags.SaveFramePointer) == 0)
                    {
                        FSData.Flags |= x86FuncScopeFlags.SaveFramePointer;
                        ReCalc = true;
                    }
                }

				CalcCount++;
			} while (ReCalc || !CheckMem2Mem(Expressions, DataLocChecker));
			/*
			if (CalcCount > 8)
				Console.WriteLine("CalcCount(" + Scope.Function.AssemblyName + "): " + CalcCount + ", ");
			*/

			return ToCopy;
		}

		static x86DataLocation[] GetPossibleLocations(FunctionScope Scope,
			x86DataLocationType Type, int Size, x86DataList CantBe = null)
		{
			var State = Scope.State;
			var Arch = State.Arch as x86Architecture;
			var Data = Scope.Data.Get<x86FuncScopeData>();
			var Ret = new List<x86DataLocation>();

			if ((Type & x86DataLocationType.General) != 0)
			{
				var Mask = new x86RegisterMask(Size);
				var HighMask = new x86RegisterMask(1, 1);

				for (var i = 0; i < Arch.RegCount; i++)
					if (i != 4)
					{
						if (Arch.IsGRegisterExists(i, Mask))
						{
							if (CantBe == null || CantBe.GRegisters.IsFree(i, new x86RegisterMask(Size)))
								Ret.Add(new x86GRegLocation(Arch, i, Size));
						}

						if (Size == 1 && Arch.IsGRegisterExists(i, HighMask))
						{
							if (CantBe == null || CantBe.GRegisters.IsFree(i, HighMask))
								Ret.Add(new x86GRegLocation(Arch, i, HighMask));
						}
					}
			}

			else if ((Type & x86DataLocationType.SSEReg) != 0)
			{
				for (var i = 0; i < Arch.RegCount; i++)
				{
					if (CantBe == null || CantBe.SSERegisters.IsFree(i))
						Ret.Add(new x86SSERegLocation(Arch, i, Math.Max(16, Size)));
				}
			}

			return Ret.ToArray();
		}

		static void ProcessParam(LocalVariable Id, List<x86MoveStruct> ToCopy)
		{
			var IdData = Id.Data.Get<x86IdentifierData>();
			if (!ProcessRegParam(Id, IdData))
				ProcessMemoryParam(Id, IdData);

			IdData.CheckLocation();
            if (IdData.Location != IdData.ParamLocation)
            {
                ToCopy.Add(new x86MoveStruct(IdData.Location, IdData.ParamLocation, 
					new x86TemporaryData(), x86ExecutorType.All, Id.TypeOfSelf));
            }
		}

		static void ProcessMemoryParam(LocalVariable Id, x86IdentifierData IdData)
		{
			var FS = Id.Container.FunctionScope;
			var FSData = FS.Data.Get<x86FuncScopeData>();
			var Allocator = FSData.Allocator;
			var Arch = Id.Container.State.Arch as x86Architecture;
			var FuncType = FS.Type;

			if (IdData.ParamLocation.IsMemory(x86OverlappingMode.Partial) &&
				(IdData.Flags & x86IdentifierFlags.CantBeInReg) == 0)
			{
				var DataCalcPos = x86Identifiers.GetPossibleLocations(Id, IdData);
				DataCalcPos &= ~x86DataLocationType.Memory;

				if (DataCalcPos != x86DataLocationType.None)
				{
					if (IdData.ReferenceCount > 1 && GetRegisterForVariable(Id))
					{
						Allocator.SetUsed(IdData.Location);
						return;
					}

					if (IdData.ReferenceCount > 2)
					{
                        var Type = Id.TypeOfSelf.RealId as Type;
                        IdData.Location = Allocator.Allocate(Type, DataCalcPos);
						if (IdData.Location != null) return;
					}
				}
			}

			IdData.Location = IdData.ParamLocation;
		}

		static bool ProcessRegParam(LocalVariable Id, x86IdentifierData IdData)
		{
			var FS = Id.Container.FunctionScope;
			var FSData = FS.Data.Get<x86FuncScopeData>();
			var Allocator = FSData.Allocator;
			var Arch = Id.Container.State.Arch as x86Architecture;
			var UsedToPassParams = FSData.UsedToPassParams;
			var FuncType = FS.Type;

			if (IdData.ParamLocation is x86MemoryLocation)
				return false;

			if ((IdData.Flags & x86IdentifierFlags.CantBeInReg) == 0)
			{
				if (!GetRegisterForVariable(Id, IdData.ParamLocation) || IdData.Location != IdData.ParamLocation)
					IdData.Flags |= x86IdentifierFlags.ParamLocUsable;
			}
			else
			{
				IdData.Flags |= x86IdentifierFlags.ParamLocUsable;
			}

			if (IdData.Location == null)
			{
                var Type = Id.TypeOfSelf.RealId as Type;
				if (IdData.ReferenceCount <= 2)
				{
                    IdData.Location = Allocator.Allocate(Type, x86DataLocationType.Memory);
				}
				else
				{
					var DataCalcPos = x86Identifiers.GetPossibleLocations(Id, IdData);
                    IdData.Location = Allocator.Allocate(Type, DataCalcPos);
				}
			}
			else
			{
				Allocator.SetUsed(IdData.Location);
			}

			if (Id == FS.SelfVariable && FS.BaseVariable != null)
			{
				var BaseIdData = FS.BaseVariable.Data.Get<x86IdentifierData>();
				BaseIdData.Location = IdData.Location;
			}

			return true;
		}

		public static bool GetRegisterForVariable(LocalVariable Id, x86DataLocation Preferred)
		{
			return GetRegisterForVariable(Id, new List<x86DataLocation>() { Preferred },
				x => x86DataLocations.Select(x, Preferred));
		}

		public static bool GetRegisterForVariable(LocalVariable Id, List<x86DataLocation> List = null,
			Func<x86DataLocation[], x86DataLocation> Selector = null)
		{
			var Arch = Id.Container.State.Arch as x86Architecture;
			var IdData = Id.Data.Get<x86IdentifierData>();
			if (List == null) List = new List<x86DataLocation>();

			int SingleLocSize;
			var DataCalcLoc = x86Identifiers.GetPossibleLocations(Id, IdData);
			if ((DataCalcLoc & x86DataLocationType.SSEReg) != 0) SingleLocSize = Arch.SSERegSize;
			else if ((DataCalcLoc & x86DataLocationType.General) != 0) SingleLocSize = Arch.RegSize;
			else SingleLocSize = int.MaxValue;

            var Type = Id.TypeOfSelf.RealId as Type;
            var PossibleLocSizes = Math.Min(Type.Size, SingleLocSize);
			var Possible = GetPossibleLocations(Id.Container.FunctionScope,
				DataCalcLoc, PossibleLocSizes, IdData.LocationCantBe);

            if (Type.Size > SingleLocSize)
			{
                var PartCount = (Type.Size - 1) / SingleLocSize + 1;
				var MemberLocs = new x86DataLocation[PartCount];

				for (var i = 0; i < Possible.Length; i++)
				{
					for (var j = 0; j < MemberLocs.Length - 1; j++)
						MemberLocs[j] = MemberLocs[j + 1];

					MemberLocs[MemberLocs.Length - 1] = Possible[i];
					if (MemberLocs[0] != null)
					{
                        var Loc = new x86MultiLocation(Arch, Type.Size, MemberLocs.ToArray());
						if (!x86DataLocations.Contains(List, Loc)) List.Add(Loc);
					}
				}
			}
			else
			{
				for (var i = 0; i < Possible.Length; i++)
				{
					if (!x86DataLocations.Contains(List, Possible[i]))
						List.Add(Possible[i]);
				}
			}

			return TestLocations(Id, List.ToArray(), Selector);
		}

		public static bool TestLocations(LocalVariable Id, x86DataLocation[] Possible,
			Func<x86DataLocation[], x86DataLocation> Selector = null)
		{
			var FS = Id.Container.FunctionScope;
			var IdData = Id.Data.Get<x86IdentifierData>();
			var TestedLocs = new x86TestedIdLocations(Id, Possible);
			var Checker = new x86OverwritingChecker(x86CheckerFlags.NoBraches, FS, TestedLocs);
			if ((Checker.Process() & CodeContextResult.Failed) != 0) return false;

			var Locations = TestedLocs.GetSucceededLocations();
			if (Locations.Length == 0) return false;
			else if (Selector == null) IdData.Location = Locations[0];
			else IdData.Location = Selector(Locations);
			return IdData.Location != null;;
		}

		static void CalcParamDataLoc(FunctionScope Scope)
		{
			var Arch = Scope.State.Arch as x86Architecture;
			var Data = Scope.Data.Get<x86FuncScopeData>();
			var CallConv = Scope.Type.CallConv;
			var x86CallConv = Arch.GetCallingConvention(CallConv);
			var Params = Scope.Parameters;
			var RegSize = Arch.RegSize;

			var DS = new x86DataSequence(Arch, x86CallConv.ParameterSequence);
			DS.StoredDataList = new x86DataList(Arch);

			if ((Data.Flags & x86FuncScopeFlags.RetAddressInParams) != 0)
			{
				var RetVarData = Data.ReturnVariable.Data.Get<x86IdentifierData>();
				RetVarData.ParamLocation = DS.GetPosition(Scope, Arch.RegSize);
				Data.ReturnVariable.Data.Set(RetVarData);
			}

			if (Scope.SelfVariable != null)
			{
				var SelfIdData = Scope.SelfVariable.Data.Get<x86IdentifierData>();
				SelfIdData.ParamLocation = DS.GetPosition(Scope, Arch.RegSize);
				Scope.SelfVariable.Data.Set(SelfIdData);

				if (Scope.BaseVariable != null)
				{
					var BaseIdData = Scope.BaseVariable.Data.Get<x86IdentifierData>();
					BaseIdData.ParamLocation = SelfIdData.ParamLocation;
				}
			}

			if (Params.Count > 0)
			{
				var Processed = new bool[Params.Count];
				var Types = Scope.Type.GetTypes();

				Arch.ProcessRegisterParams(Types, CallConv, (Index, Pos) =>
				{
					var IdData = Params[Index].Data.Get<x86IdentifierData>();
					IdData.ParamLocation = Pos;
					Processed[Index] = true;
				}, DS);

				for (var i = 0; i < Params.Count; i++)
					if (!Processed[i])
					{
						var IdData = Params[i].Data.Get<x86IdentifierData>();
                        var ParamType = Params[i].TypeOfSelf.RealId as Type;
                        IdData.ParamLocation = DS.GetPosition(Scope, ParamType);
						Params[i].Data.Set(IdData);
					}
			}

			DS.AlignStack(Arch.RegSize);
			Data.UsedToPassParams = DS.StoredDataList;
		}

	}

}

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)

Share

About the Author

Dávid Kocsis
Student
Hungary Hungary
I've been programming for 8 years. My first big project was a remake of a nice bomberman game called Dyna Blaster. When i was little i played a lot with it. Now i'm working on a new programming language and code generator.
I would like to work with someone, so feel free to contact me about it.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 1 Jan 2013
Article Copyright 2012 by Dávid Kocsis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid