Click here to Skip to main content
15,881,715 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 373.1K   2.7K   153  
A new general purpose language that aims to be fast, high level and simple to use.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Numerics;
using Bird.NativeCode;

namespace Bird.x86
{
	public struct x86IdReference
	{
		public int ContainerIndex;
		public int ExpressionIndex;
		public int ExecutionNumber;

		public x86IdReference(int ContainerIndex, int ExpressionIndex, int ExecutionNumber)
		{
			this.ContainerIndex = ContainerIndex;
			this.ExpressionIndex = ExpressionIndex;
			this.ExecutionNumber = ExecutionNumber;
		}

		public static int Compare(x86IdReference Ref1, x86IdReference Ref2)
		{
			if (Ref1.ContainerIndex < Ref2.ContainerIndex) return -1;
			if (Ref1.ContainerIndex > Ref2.ContainerIndex) return 1;

			if (Ref1.ExpressionIndex < Ref2.ExpressionIndex) return -1;
			if (Ref1.ExpressionIndex > Ref2.ExpressionIndex) return 1;

			if (Ref1.ExecutionNumber < Ref2.ExecutionNumber) return -1;
			if (Ref1.ExecutionNumber > Ref2.ExecutionNumber) return 1;
			return 0;
		}

		public static x86IdReference Min(x86IdReference Ref1, x86IdReference Ref2)
		{
			return Compare(Ref1, Ref2) < 0 ? Ref1 : Ref2;
		}

		public static x86IdReference Max(x86IdReference Ref1, x86IdReference Ref2)
		{
			return Compare(Ref1, Ref2) < 0 ? Ref2 : Ref1;
		}
	}

	public struct x86IdReferenceRange
	{
		public x86IdReference Min, Max;

		public void Set(x86IdReference Reference)
		{
			Min = Max = Reference;
		}

		public void Add(x86IdReference Reference)
		{
			Min = x86IdReference.Min(Min, Reference);
			Max = x86IdReference.Max(Max, Reference);
		}

		public bool Contains(x86IdReference Reference)
		{
			return x86IdReference.Compare(Min, Reference) >= 0 &&
				x86IdReference.Compare(Max, Reference) <= 0;
		}

		public bool Intersects(x86IdReferenceRange Range)
		{
			return Contains(Range.Min) || Contains(Range.Max);
		}
	}

	public class x86CallingConvention
	{
		public x86RegisterList SavedGRegs;
		public x86RegisterList SavedSSERegs;
		public x86SequenceOptions ParameterSequence;
		public x86SequenceOptions AllocationSequence;
		public bool StackCleanupByCaller;
		public int StackAlignment;
		public int ParameterAlignment;

		public bool IsSavedRegister(x86DataLocation Location)
		{
			if (Location is x86GRegLocation)
			{
				var GReg = Location as x86GRegLocation;
				return SavedGRegs[GReg.Index];
			}
			else if (Location is x86SSERegLocation)
			{
				var SSEReg = Location as x86SSERegLocation;
				return SavedSSERegs[SSEReg.Index];
			}
			else
			{
				return true;
			}
		}
	}

	public class x86AsmModifier : Modifier
	{
		public x86AsmModifier(CodeString Code)
			: base(Code)
		{
		}

		public override bool Apply(Identifier Id)
		{
			var State = Id.Container.State;
			if (!(Id is Function))
			{
				State.Messages.Add(MessageId.NotExpected, Code);
				return false;
			}

			var IdData = Id.Data.GetOrCreate<x86FunctionData>(Id);
			IdData.AssemblyOnly = true;
			return true;
		}
	}

	public class x86AsmModifierRecognizer : IModRecognizer
	{
		public static string String = "asm";

		public SimpleRecResult Recognize(IdContainer Container, ref CodeString Code, List<Modifier> Out)
		{
			if (Code.StartsWith(String, new IdCharCheck(true)))
			{
				var State = Container.State;
				var ModCode = Code.Substring(0, String.Length);

				for (var i = 0; i < Out.Count; i++)
					if (Out[i] is x86AsmModifier)
					{
						State.Messages.Add(MessageId.NotExpected, ModCode);
						return SimpleRecResult.Failed;
					}

				Out.Add(new x86AsmModifier(ModCode));
				Code = Code.Substring(String.Length).Trim();
			}

			return SimpleRecResult.Unknown;
		}
	}

	public struct x86ConstString
	{
		public string String;
		public int Label;

		public x86ConstString(string String, int Label)
		{
			this.String = String;
			this.Label = Label;
		}
	}

	public class x86GlobalContainerData
	{
		public GlobalContainer Scope;
		public List<x86ConstString> ConstStrings = new List<x86ConstString>();

		ClassType _x86HelperClass;
		public ClassType Getx86HelperClass()
		{
			lock (this)
			{
				if (_x86HelperClass != null) return _x86HelperClass;
				_x86HelperClass = Identifiers.GetByFullNameFast<ClassType>(Scope, "Internals._x86Helper");
				return _x86HelperClass;
			}
		}

		public Identifier GetHelperId(string Name, GetIdOptions Options)
		{
			var HelperClass = Getx86HelperClass();
			if (HelperClass == null) return null;

			var CName = new CodeString("_x86Helper." + Name);
			var Id = Identifiers.GetMember(Scope.State, HelperClass, Name, CName, Options);
			Id.Used = true;
			return Id;
		}

		public Identifier GetHelperId(string Name)
		{
			return GetHelperId(Name, GetIdOptions.Default);
		}

		public Function GetHelperFunction(string Name)
		{
			var Options = GetIdOptions.Default;
			Options.Func = x => x is Function;

			return GetHelperId(Name, Options) as Function;
		}

		public Variable GetHelperVariable(string Name)
		{
			var Options = GetIdOptions.Default;
			Options.Func = x => x is Variable;

			return GetHelperId(Name, Options) as Variable;
		}

		public x86GlobalContainerData(GlobalContainer Scope)
		{
			this.Scope = Scope;
		}
	}

	public class x86ConditionalJump : JumpInstruction
	{
		public string Condition;

		public x86ConditionalJump(int Label, string Condition)
			: base(Label)
		{
			this.Condition = Condition;
		}
	}

	public struct x86MoveStruct
	{
		public x86DataLocation Dst;
		public x86DataLocation Src;
		public x86TemporaryData TempData;
		public x86ExecutorType Executor;
		public x86StoredDataType StoredDataType;
		
		public x86MoveStruct(x86DataLocation Dst, x86DataLocation Src, x86TemporaryData TempData,
			x86ExecutorType Executor, Identifier Type)

			: this(Dst, Src, TempData, Executor, x86Identifiers.GetStoredDataType(Type))
		{

		}

		public x86MoveStruct(x86DataLocation Dst, x86DataLocation Src, x86TemporaryData TempData,
			x86ExecutorType Executor, x86StoredDataType StoredDataType)
		{
			this.Dst = Dst;
			this.Src = Src;
			this.TempData = TempData;
			this.Executor = Executor;
			this.StoredDataType = StoredDataType;
		}

		public x86MoveStruct Inverse
		{
			get { return new x86MoveStruct(Src, Dst, TempData, Executor, StoredDataType); }
		}
	}

	public class x86MoveCondBranch : CondBranch
	{
		public x86MoveStruct Struct;

		public x86MoveCondBranch(x86DataLocation Dst, x86DataLocation Src, x86TemporaryData TempData,
			x86ExecutorType Executor, Identifier Type)
		{
			Struct = new x86MoveStruct(Dst, Src, TempData, Executor, Type);
		}

		public x86MoveCondBranch(x86DataLocation Dst, x86DataLocation Src, x86TemporaryData TempData,
			x86ExecutorType Executor, x86StoredDataType StoredDataType)
		{
			Struct = new x86MoveStruct(Dst, Src, TempData, Executor, StoredDataType);
		}

		public x86MoveCondBranch(x86MoveStruct Struct)
		{
			this.Struct = Struct;
		}
	}

	[Flags]
	public enum x86IdentifierFlags : byte
	{
		HasReferenceRange = 1,
		WholeContainerUsed = 2,
		CantBeInReg = 4,
		ParamLocUsable = 8,
		NeededToBeMem = 16,
	}

	public class x86IdentifierData
	{
		public Identifier Identifier;
		public LocalVariable PreferredIdForLocation;
		public x86DataLocation Location;
		public x86DataLocation ParamLocation;
		public x86DataList LocationCantBe;
		public x86IdReferenceRange ReferenceRange;
		public int ReferenceCount;
		public x86IdentifierFlags Flags;

		public x86IdentifierData(Identifier Identifier)
		{
			this.Identifier = Identifier;
		}

		public void CheckLocation()
		{
			if (Location == null)
				throw new InvalidOperationException();

            var Type = Identifier.TypeOfSelf.RealId as Type;
            if (Location.Size != Type.Size && !(Location is x86SSERegLocation))
				throw new ApplicationException();

			if (Location is x86MemoryLocation)
				Flags |= x86IdentifierFlags.NeededToBeMem;
			//else if ((Flags & x86IdentifierFlags.NeededToBeMem) != 0)
				//throw new ApplicationException();
		}

		public void Reset()
		{
			Location = null;
		}

		public void GetStartEnd(out int Start, out int End)
		{
			if ((Flags & x86IdentifierFlags.WholeContainerUsed) != 0)
			{
				Start = 0;
				End = Identifier.Container.Children.Count - 1;
			}
			else if ((Flags & x86IdentifierFlags.HasReferenceRange) != 0)
			{
				Start = ReferenceRange.Min.ContainerIndex;
				End = ReferenceRange.Max.ContainerIndex;
			}
			else
			{
				Start = 0;
				End = -1;
			}
		}

		public void SetParameterUsed()
		{
			var Data = Identifier.Container.Data.Get<x86IdContainerData>();
			Data.UsedByParams.SetUsed(ParamLocation);

			int Start, End;
			GetStartEnd(out Start, out End);

			for (var j = Start; j <= End; j++)
			{
				Identifier.Container.Children[j].ForEach(x =>
				{
					var xData = x.Data.Get<x86IdContainerData>();
					xData.UsedByParams.SetUsed(ParamLocation);
				});
			}
		}

		public void SetLocationUsed(bool OnlyChildContainers = false)
		{
			if (!OnlyChildContainers)
			{
				var Data = Identifier.Container.Data.Get<x86IdContainerData>();
				Data.Allocator.SetUsed(Location);
			}

			int Start, End;
			GetStartEnd(out Start, out End);

			for (var j = Start; j <= End; j++)
			{
				Identifier.Container.Children[j].ForEach(x =>
				{
					var xData = x.Data.Get<x86IdContainerData>();
					xData.Allocator.SetUsed(Location);
				});
			}
		}
	}

	public delegate void ProcessAsCallFunc(int Index, x86DataLocation Pos);

	[Flags]
	public enum x86Extensions
	{
		None = 0,
		LongMode = 1,
		FPU = 2,
		SSE = 4,
		SSE2 = 8,
		SSE3 = 16,
		SSSE3 = 32,
		SSE41 = 64,
		SSE42 = 128,
		SSE4ABM = 256,
		SSE4a = 512,
		AVX = 1024,
		CVT16 = 2048,
		XOP = 4096,
		FMA3 = 8192,
		FMA4 = 16384,
		AES = 32768,
		CLMUL = 65536,
		AVX2 = 131072,

		Default = FPU | SSE | SSE2 | SSE3,
		Default64 = LongMode | Default,
	}

	public enum x86FloatingPointMode : byte
	{
		Disabled,
		FPU,
		SSE
	}

	public class x86InstructionEncoder : InstructionEncoder
	{
		public static string EncodeToText(string Instruction, params object[] Parameters)
		{
			if (Parameters.Length > 0 && Parameters[0] == null)
				Parameters[0] = string.Empty;

			return "\t" + Instruction + " " + string.Join(", ", Parameters) + "\n";
		}

		public override string EncodeToText(Instruction Instruction)
		{
			if (Instruction is StrInstruction)
			{
				var StrIns = Instruction as StrInstruction;
				return StrIns.Instruction;
			}
			else if (Instruction is LabelInstruction)
			{
				var LabelIns = Instruction as LabelInstruction;
				return LabelIns.LabelName + ":\n";
			}
			else if (Instruction is JumpInstruction)
			{
				if (Instruction is x86ConditionalJump)
				{
					var JumpIns = Instruction as x86ConditionalJump;
					return EncodeToText("j" + JumpIns.Condition, JumpIns.LabelName);
				}
				else
				{
					var JumpIns = Instruction as JumpInstruction;
					return EncodeToText("jmp", JumpIns.LabelName);
				}
			}
			else
			{
				throw new NotImplementedException();
			}
		}
	}

	public class x86Architecture : IArchitecture, INCArchitecture
	{
		public struct CallingConventionsList
		{
			public x86CallingConvention CDecl;
			public x86CallingConvention StdCall;
			public x86CallingConvention BirdCall;
		}

		public CompilerState State;
		public x86Extensions Extensions;
		public x86FloatingPointMode FloatingPointMode;
		public CallingConventionsList CallingConventions;

		public int SSERegSize { get { return (Extensions & x86Extensions.AVX) != 0 ? 32 : 16; } }
		public int RegSize { get { return (Extensions & x86Extensions.LongMode) != 0 ? 8 : 4; } }
		public int RegCount { get { return (Extensions & x86Extensions.LongMode) != 0 ? 16 : 8; } }
		public int MaxStructPow2Size { get { return (Extensions & x86Extensions.SSE) != 0 ? SSERegSize : RegSize; } }
		public int ByteRegCount { get { return (Extensions & x86Extensions.LongMode) != 0 ? 14 : 4; } }
		public x86RegisterMask RegisterMask { get { return new x86RegisterMask(0, RegSize); } }

		public x86ExecutorType GetDefaultExecutor(Identifier Identifier)
		{
			var TypeKind = x86Identifiers.GetTypeKind(Identifier);
			return GetDefaultExecutor(TypeKind);
		}

		public x86ExecutorType GetDefaultExecutor(x86TypeKind TypeKind)
		{
			if (x86Identifiers.IsFloatTypeKind(TypeKind))
			{
				if (FloatingPointMode == x86FloatingPointMode.FPU)
					return x86ExecutorType.FPU;
				else if (FloatingPointMode == x86FloatingPointMode.SSE) 
					return x86ExecutorType.SSE;
				
				return x86ExecutorType.None;
			}

			return x86ExecutorType.SSE | x86ExecutorType.General;
		}

		public x86CallingConvention GetCallingConvention(CallingConvention Conv)
		{
			if (Conv == CallingConvention.BirdCall) return CallingConventions.BirdCall;
			else if (Conv == CallingConvention.StdCall) return CallingConventions.StdCall;
			else if (Conv == CallingConvention.CDecl) return CallingConventions.CDecl;
			else throw new ApplicationException();
		}

		public x86CallingConvention GetCallingConvention(Identifier Id)
		{
			var FuncType = Id.TypeOfSelf.RealId as TypeOfFunction;
			return GetCallingConvention(FuncType.CallConv);
		}

		public static x86CallingConvention GetCallingConvention(bool LongMode,
			OperatingSystem OperatingSystem, CallingConvention CallingConvention)
		{
			x86CallingConvention RetValue;

			if (LongMode)
			{
				if (OperatingSystem == OperatingSystem.Windows)
				{
					RetValue = new x86CallingConvention();
					RetValue.SavedGRegs = new x86RegisterList()
					{
						UsedRegs = new bool[]
						{ 
							false, false, false, true, false, true, true, true,
							false, false, false, false, true, true, true, true,
						}
					};

					RetValue.SavedSSERegs = new x86RegisterList()
					{
						UsedRegs = new bool[]
						{ 
							false, false, false, false, false, false, true, true,
							true, true, true, true, true, true, true, true,
						}
					};

					RetValue.AllocationSequence = new x86SequenceOptions()
					{
						GRegisters = new int[]
						{
							0, 2, 1, 8, 9, 10, 11, 
							3, 5, 6, 7, 12, 13, 14, 15
						},

						SSERegisters = new int[]
						{
							0, 1, 2, 3, 4, 5,
							6, 7, 8, 9, 10, 12, 13, 14, 15
						},

						AllowPartRegisters = true,
						Align = 1,
					};

					RetValue.ParameterSequence = new x86SequenceOptions()
					{
						GRegisters = new int[] { 2, 1, 8, 9 },
						SSERegisters = new int[] { 0, 1, 2, 3 },
						AllowPartRegisters = false,
						Align = 8,
					};

					RetValue.StackCleanupByCaller = false;
					RetValue.StackAlignment = LongMode ? 8 : 4;
					RetValue.ParameterAlignment = LongMode ? 8 : 4;
				}
				else
				{
					throw new NotImplementedException();
				}
			}
			else
			{
				var SavedGRegisters = new x86RegisterList()
				{
					UsedRegs = new bool[]
					{ 
						false, false, false, true, false, true, true, true,
					}
				};

				var GRegAllocationSequence = new int[]
				{
					0, 2, 1, 3, 5, 6, 7,
				};

				if (CallingConvention == CallingConvention.BirdCall)
				{
					RetValue = new x86CallingConvention();
					RetValue.SavedGRegs = SavedGRegisters;

					RetValue.SavedSSERegs = new x86RegisterList()
					{
						UsedRegs = new bool[]
						{
							false, false, false, false, true, true, true, true,
						}
					};

					RetValue.AllocationSequence = new x86SequenceOptions()
					{
						GRegisters = GRegAllocationSequence,
						SSERegisters = new int[] { 0, 1, 2, 3, 4, 5, 6, 7 },
						AllowPartRegisters = true,
						Align = 1,
					};

					RetValue.ParameterSequence = new x86SequenceOptions()
					{
						GRegisters = new int[] { 0, 2, 1 },
						SSERegisters = new int[] { 0, 1, 2 },
						AllowPartRegisters = true,
						Align = 4,
					};

					RetValue.StackCleanupByCaller = false;
					RetValue.StackAlignment = LongMode ? 8 : 4;
					RetValue.ParameterAlignment = LongMode ? 8 : 4;
				}
				else
				{
					RetValue = new x86CallingConvention();
					RetValue.SavedGRegs = SavedGRegisters;
					RetValue.SavedSSERegs = new x86RegisterList() { UsedRegs = new bool[8] };

					RetValue.AllocationSequence = new x86SequenceOptions()
					{
						GRegisters = GRegAllocationSequence,
						SSERegisters = new int[] { 0, 1, 2, 3, 4, 5, 6, 7 },
						AllowPartRegisters = true,
						Align = 1,
					};

					RetValue.ParameterSequence = new x86SequenceOptions()
					{
						GRegisters = new int[] { },
						SSERegisters = new int[] { },
						AllowPartRegisters = false,
						Align = 4,
					};

					RetValue.StackCleanupByCaller = CallingConvention == CallingConvention.CDecl;
					RetValue.StackAlignment = LongMode ? 8 : 4;
					RetValue.ParameterAlignment = LongMode ? 8 : 4;
				}
			}

			return RetValue;
		}

		void InitializeCallingConventions()
		{
			var OS = State.OperatingSystem;
			var LongMode = (Extensions & x86Extensions.LongMode) != 0;

			CallingConventions.BirdCall = GetCallingConvention(LongMode, OS, CallingConvention.BirdCall);
			CallingConventions.CDecl = GetCallingConvention(LongMode, OS, CallingConvention.CDecl);
			CallingConventions.StdCall = GetCallingConvention(LongMode, OS, CallingConvention.StdCall);
		}

		public bool SetupPlugin(PluginRoot Plugin)
		{
			var x86Plugins = new IExpressionPlugin[]
			{
				new x86ExpressionPlugin(Plugin),
				new x86Plugin(Plugin),
			};

			Plugin.Plugins = Plugin.Plugins.Union(x86Plugins).ToArray();
			return true;
		}

		public bool ProcessContainer(IdContainer Container)
		{
			return x86Functions.ProcessContainer(Container);
		}

		public bool Compile(CompilerState State, CodeFile[] CodeFiles)
		{
			this.State = State;
			Initialize();

			var Language = State.Language;
            var OldModRecs = Language.ModRecognizers;
            Language.ModRecognizers = OldModRecs.Union(new x86AsmModifierRecognizer()).ToArray();

			var Scope = State.GlobalContainer;
			var Data = new x86GlobalContainerData(Scope);
			Scope.Data.Set(Data);

            var Preprocessor = Scope.Preprocessor;
            DefineExtensions(Preprocessor, Extensions);
            Preprocessor.Define("FP_MODE", FloatingPointMode.ToString());
			if (!Scope.Process()) return false;

			Write(State.CodeOut, SW => GetAsmCode(State, SW));
			Scope.Data.Remove<x86GlobalContainerData>();

            Language.ModRecognizers = OldModRecs;
			return true;
		}

        public static bool DefineExtensions(Preprocessor Preprocessor, x86Extensions Extensions)
		{
			var RetValue = true;
			foreach (var e in Enum.GetValues(typeof(x86Extensions)))
			{
				var EnumVal = (x86Extensions)e;
				if ((Extensions & EnumVal) != 0)
				{
					string Name;
					if (EnumVal == x86Extensions.LongMode) Name = "LONG_MODE";
					else Name = EnumVal.ToString().ToUpper();

                    if (!Preprocessor.Define(Name))
						RetValue = false;
				}
			}

			return RetValue;
		}

		void Write(Stream Stream, Action<StreamWriter> Func)
		{
			var StreamWriter = new StreamWriter(Stream);
			Func(StreamWriter);
			StreamWriter.Flush();
		}

		public bool IsSimpleCompareNode(ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			if (OpNode == null) return true;

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

			for (var i = 0; i < Ch.Length; i++)
				if (Ch[i] is OpExpressionNode)
				{
					var OpChi = Ch[i] as OpExpressionNode;
					var ChiOp = OpChi.Operator;
					var ChiCh = OpChi.Children;

					if (ChiOp != Operator.Member && ChiOp != Operator.Index)
						return false;

					for (var j = 0; j < ChiCh.Length; j++)
						if (ChiCh[j] is OpExpressionNode) return false;
				}

			if (Operators.IsRelEquality(Op))
				return true;

			if (Op == Operator.Unknown)
			{
				var Data = Node.Data.Get<x86NodeData>();
				if (x86Expressions.IsConditionOp(Data.Operator))
					return true;
			}

			return false;
		}

		bool ProcessAssembly(Function Function)
		{
			var Container = Function.Container;
			var State = Container.State;
			var Handlers = State.Language.GlobalHandlers;
			var Data = Function.Data.Get<x86FunctionData>();
			var Scope = Function.FunctionScope;
			var Code = Scope.Code;

			var RetValue = true;
			var Assembly = new StringBuilder();
			var Labels = new Dictionary<string, int>();

			foreach (var Line in Code.EnumLines())
			{
				var NLine = Line;
				var CommentPos = NLine.Find(';', Handlers: Handlers);
				if (CommentPos != -1)
					NLine = NLine.Substring(0, CommentPos);

				NLine = NLine.Trim();
				if (NLine.Length == 0) continue;

				var LabelPos = NLine.Find(':', Handlers: Handlers);
				if (LabelPos != -1)
				{
					var LabelName = NLine.TrimmedSubstring(State, 0, LabelPos);
					if (!LabelName.IsValid) { RetValue = false; continue; }

					if (!LabelName.IsValidIdentifierName)
					{
						State.Messages.Add(MessageId.NotValidName, LabelName);
						RetValue = false; continue;
					}

					foreach (var e in Labels)
						if (LabelName.IsEqual(e.Key))
						{
							State.Messages.Add(MessageId.LabelAlreadyDefined, LabelName);
							RetValue = false;
							break;
						}

					if (!RetValue) continue;
					Labels.Add(LabelName.ToString(), State.AutoLabel);
				}

				var Pos = 0;
				if (LabelPos == -1)
					Assembly.Append("\t");

				foreach (var e in NLine.EnumFind("$["))
				{
					var FromBracket = NLine.Substring(e + 1);
					var BracketPos = FromBracket.GetBracketPos(State);
					if (BracketPos == -1) { RetValue = false; break; }

					var IdName = FromBracket.Substring(1, BracketPos - 1).Trim();
					var Id = Identifiers.Recognize(Container, IdName);
					if (Id == null) { RetValue = false; break; }
					
					Assembly.Append(NLine.Substring(Pos, e - Pos));
					Assembly.Append(x86Expressions.GetLocation(this, Id));
					Pos = e + BracketPos + 2;
				}

				Assembly.Append(NLine.Substring(Pos) + "\n");
			}

			if (Labels.Count > 0)
			{
				var Pos = 0;
				var String = Assembly.ToString();
				var StringRange = new StringSlice(String);
				Assembly.Clear();

				foreach (var Word in StringRange.EnumWords())
				{
					foreach (var Label in Labels)
						if (Word.IsEqual(Label.Key))
						{
							Assembly.Append(String.Substring(Pos, Word.Index - Pos));
							Assembly.Append("_" + Label.Value);
							Pos = Word.Index + Word.Length;
						}
				}

				Assembly.Append(String.Substring(Pos));
			}

			Data.Assembly = Assembly.ToString();
			return RetValue;
		}

		public void GetAssembly(CodeGenerator CG, Function Function)
		{
			var Data = Function.Data.Get<x86FunctionData>();
			CG.InsContainer.Add(Data.Assembly);
		}

		public bool ProcessFunction(Function Func)
		{
			var Data = Func.Data.Get<x86FunctionData>();
			var Scope = Func.FunctionScope;

			if (Data.AssemblyOnly) return ProcessAssembly(Func);
			else return x86Functions.ProcessFunction(Scope);
		}

		public bool CreateAssembly(Function Func)
		{
			var Data = Func.Data.Get<x86FunctionData>();
			var Scope = Func.FunctionScope;

			if (!Data.AssemblyOnly) 
				x86Functions.CreateAssembly(Scope);

			return true;
		}

		public bool ProcessIdentifier(Identifier Id)
		{
			if (Id is GlobalVariable)
			{
				var Var = Id as GlobalVariable;
				var Type = Var.TypeOfSelf.RealId as Type;

				var Data = Id.Data.GetOrCreate<x86IdentifierData>(Var);
				var LabelPos = new x86NamedLabelPosition(this, Id.AssemblyName);
				Data.Location = new x86IndexLocation(this, 0, Type.Size, LabelPos);
			}
			else if (Id is Function)
			{
				var Func = Id as Function;

				var Data = Id.Data.GetOrCreate<x86FunctionData>(Func);
				Data.Location = new x86NamedLabelPosition(this, Id.AssemblyName);
				if (Data.AssemblyOnly)
				{
					Func.FunctionScope.Flags |= FunctionScopeFlags.DisableParsing;
					Func.FunctionScope.Flags |= FunctionScopeFlags.DisableCodeCheck;
					Func.FunctionScope.Flags |= FunctionScopeFlags.DisableAddingRetCommand;
				}
			}

			return true;
		}

		private void GetSectionCode(IdContainer Container, string Section,
			TextWriter Out, Action<x86CodeGenerator> Func)
		{
			var Compiler = new x86CodeGenerator(Container);
			Func(Compiler);

			var InsEncoder = new x86InstructionEncoder();
			var Code = Compiler.InsContainer.EncodeToText(InsEncoder);
			if (Code.Length > 0)
			{
				Out.Write(Section);
				Out.Write(Code);
			}
		}

		private void GetAsmCode(CompilerState State, TextWriter Out)
		{
			var Scope = State.GlobalContainer;
			var Data = Scope.Data.Get<x86GlobalContainerData>();

			if (State.Format == ImageFormat.MSCoff)
			{
				if ((Extensions & x86Extensions.LongMode) != 0)
					Out.Write("\tformat MS64 COFF\n");
				else Out.Write("\tformat MS COFF\n");
			}
			else if (State.Format == ImageFormat.GUI)
			{
				if ((Extensions & x86Extensions.LongMode) != 0)
					Out.Write("\tformat PE64 GUI 4.0\n");
				else Out.Write("\tformat PE GUI 4.0\n");
			}
			else if (State.Format == ImageFormat.Console)
			{
				if ((Extensions & x86Extensions.LongMode) != 0)
					Out.Write("\tformat PE64 CONSOLE 4.0\n");
				else Out.Write("\tformat PE CONSOLE 4.0\n");
			}
			else if (State.Format == ImageFormat.DLL || State.Format == ImageFormat.AsDLL)
			{
				if ((Extensions & x86Extensions.LongMode) != 0)
					Out.Write("\tformat PE64 DLL 4.0\n");
				else Out.Write("\tformat PE DLL 4.0\n");
			}
			else
			{
				throw new ApplicationException();
			}

			var ExternCode = Scope.GetExternPublicCode();
			if (ExternCode.Length > 0) Out.Write(ExternCode);
			Out.Write("\t\n");

			// -----------------------------------------------------------------
			GetSectionCode(Scope, "section \".text\" code readable executable\n\n", Out,
				CG => Scope.GetAssembly(CG, GetAssemblyMode.Code));

			GetSectionCode(Scope, "section \".data\" data readable writeable align 32\n\n", Out,
				CG =>
				{
					Scope.GetAssembly(CG, GetAssemblyMode.InitedValues);

					for (var i = 0; i < Data.ConstStrings.Count; i++)
					{
						var e = Data.ConstStrings[i];
						CG.InsContainer.Label(e.Label);
						CG.DeclareValueString(e.String);
					}

					CG.InsContainer.Add("\n");
				});

			GetSectionCode(Scope, "section \".rdata\" data readable align 32\n\n", Out,
				CG => Scope.GetAssembly(CG, GetAssemblyMode.ReflectionData));

			GetSectionCode(Scope, "section \".bss\" data readable writeable align 32\n", Out,
				CG =>
				{
					var InsContainer = CG.ExecuteOnTempInsContainer(() =>
						Scope.GetAssembly(CG, GetAssemblyMode.UninitedValues));

#warning WARNING
					//if (InsContainer.Instructions.Count > 0)
					{
						Scope.Flags |= GlobalContainerFlags.HasUninitedValues;
						CG.InsContainer.Label("_%UninitedValues_Begin");
						CG.InsContainer.Add("\n");
						CG.InsContainer.Add(InsContainer);
						CG.Align(32);
						CG.InsContainer.Label("_%UninitedValues_End");
						CG.InsContainer.Add("\n");
					}

				});
		}

		public static bool CanBeIndexRegScale(ExpressionNode Node)
		{
			if (Node is ConstExpressionNode)
			{
				var ConstNode = Node as ConstExpressionNode;
				return CanBeIndexRegScale(ConstNode.Integer);
			}

			return false;
		}

		public static bool CanBeIndexRegScale(BigInteger Num)
		{
			return Num == 1 || Num == 2 || Num == 4 || Num == 8;
		}

		public static bool CanBeIndexRegScale(int Num)
		{
			return Num == 1 || Num == 2 || Num == 4 || Num == 8;
		}

		void ProcessRegisterParams_GReg(int Index, int Size, ProcessAsCallFunc Func, x86DataSequence DS)
		{
			if (!DS.CanAllocGReg(Size)) return;
			var Pos = (x86DataLocation)null;

			if (Size > RegSize)
			{
				var RSize = Size;
				var PartCount = (Size - 1) / RegSize + 1;
				var Positions = new x86DataLocation[PartCount];

				for (var i = 0; i < PartCount; i++)
				{
					var S = Size < RegSize ? Size : RegSize;
					var Reg = DS.GetGRegister(S);

					Positions[i] = Reg;
					Size -= S;
				}

				Pos = new x86MultiLocation(this, RSize, Positions);
			}
			else
			{
				Pos = DS.GetGRegister(Size);
			}

			Func(Index, Pos);
		}

		public static bool IsPointerType(Identifier Type)
		{
			var T = Type.RealId as Type;
			return T is ReferenceType || T is TypeOfFunction || T is PointerType || 
				(T.TypeFlags & TypeFlags.ReferenceValue) != 0;
		}

		public void ProcessRegisterParams(Type[] Params, CallingConvention CallConv, ProcessAsCallFunc Func, x86DataSequence DS = null)
		{
			if (DS == null)
			{
				var x86CallConv = GetCallingConvention(CallConv);
				DS = new x86DataSequence(this, x86CallConv.ParameterSequence);
			}

			if (CallConv == CallingConvention.BirdCall)
			{
				var Processed = new bool[Params.Length];

				for (var i = 0; i < Params.Length; i++)
					if (IsPointerType(Params[i]))
					{
						if ((x86Identifiers.GetPossibleLocations(Params[i]) & x86DataLocationType.General) != 0)
						{
							ProcessRegisterParams_GReg(i, Params[i].Size, Func, DS);
							Processed[i] = true;
						}
					}

				for (var i = 0; i < Params.Length; i++)
					if (!Processed[i])
					{
						if ((x86Identifiers.GetPossibleLocations(Params[i]) & x86DataLocationType.General) != 0)
						{
							ProcessRegisterParams_GReg(i, Params[i].Size, Func, DS);
							Processed[i] = true;
						}
					}
			}
			else
			{
				for (var i = 0; i < Params.Length; i++)
				{
					if ((x86Identifiers.GetPossibleLocations(Params[i]) & x86DataLocationType.General) != 0)
						ProcessRegisterParams_GReg(i, Params[i].Size, Func, DS);
				}
			}

			if (FloatingPointMode == x86FloatingPointMode.SSE)
			{
				for (var i = 0; i < Params.Length; i++)
					if (Params[i].RealId is FloatType)
					{
						if ((x86Identifiers.GetPossibleLocations(Params[i]) & x86DataLocationType.SSEReg) != 0)
						{
							if (!DS.CanAllocSSEReg()) break;
							Func(i, DS.GetSSERegister());
						}
					}
			}
		}

		public x86Architecture(x86Extensions Extensions = x86Extensions.Default)
		{
			this.Extensions = Extensions;

			if ((Extensions & x86Extensions.SSE2) != 0)
				FloatingPointMode = x86FloatingPointMode.SSE;
			else FloatingPointMode = x86FloatingPointMode.FPU;
		}

		void Initialize()
		{
			InitializeCallingConventions();
		}

		public static bool IsGRegister(x86DataLocation Pos, int Index)
		{
			var RegPos = Pos as x86GRegLocation;
			return RegPos != null && RegPos.Index == Index;
		}

		public bool IsGRegisterExists(int Index, int Offset, int Size)
		{
			var LongMode = (Extensions & x86Extensions.LongMode) != 0;
			if (Index < 0) throw new ArgumentOutOfRangeException("Index");

			if (Size == 1)
			{
				if (Index < 4) return Offset == 0 || Offset == 1;
				if (LongMode && Offset == 0 && Index >= 6 && Index < 16) return true;
			}
			else if (Size == 2 || Size == 4 || (Size == 8 && LongMode))
			{
				return Offset == 0 && (Index < 8 || (LongMode && Index < 16));
			}

			return false;
		}

		public bool IsGRegisterExists(int Index, x86RegisterMask Mask)
		{
			return IsGRegisterExists(Index, Mask.Offset, Mask.Size);
		}

		public static string GetTypeString(int Size)
		{
			switch (Size)
			{
				case 1: return "byte";
				case 2: return "word";
				case 4: return "dword";
				case 6: return "pword";
				case 8: return "qword";
				case 10: return "tword";
				case 16: return "dqword";
				default: return null;
			}
		}

		public static string GetDataTypeString(int Size)
		{
			switch (Size)
			{
				case 1: return "db";
				case 2: return "dw";
				case 4: return "dd";
				case 6: return "dp";
				case 8: return "dq";
				case 10: return "dt";
				default: return null;
			}
		}

		public static string GetGRegisterName(int Index, int Size)
		{
			return GetGRegisterName(Index, 0, Size);
		}

		public static string GetGRegisterName(int Index, int Offset, int Size)
		{
			if (Size == 1)
			{
				if (Offset != 0 && Offset != 1)
					return null;

				switch (Index)
				{
					case 0: return Offset == 1 ? "ah" : "al";
					case 1: return Offset == 1 ? "ch" : "cl";
					case 2: return Offset == 1 ? "dh" : "dl";
					case 3: return Offset == 1 ? "bh" : "bl";

					case 6: return Offset == 1 ? null : "sil";
					case 7: return Offset == 1 ? null : "dil";

					default:
						if (Index >= 8 && Index < 16)
							return Offset == 1 ? null : "r" + Index + "b";
						else return null;
				}
			}
			else if (Size == 2)
			{
				if (Offset != 0)
					return null;

				switch (Index)
				{
					case 0: return "ax";
					case 1: return "cx";
					case 2: return "dx";
					case 3: return "bx";
					case 4: return "sp";
					case 5: return "bp";
					case 6: return "si";
					case 7: return "di";

					default:
						if (Index >= 8 && Index < 16) return "r" + Index + "w";
						else return null;
				}
			}
			else if (Size == 4)
			{
				if (Offset != 0)
					return null;

				switch (Index)
				{
					case 0: return "eax";
					case 1: return "ecx";
					case 2: return "edx";
					case 3: return "ebx";
					case 4: return "esp";
					case 5: return "ebp";
					case 6: return "esi";
					case 7: return  "edi";

					default:
						if (Index >= 8 && Index < 16) return "r" + Index + "d";
						else return null;
				}
			}
			else if (Size == 8)
			{
				if (Offset != 0)
					return null;

				switch (Index)
				{
					case 0: return "rax";
					case 1: return "rcx";
					case 2: return "rdx";
					case 3: return "rbx";
					case 4: return "rsp";
					case 5: return "rbp";
					case 6: return "rsi";
					case 7: return "rdi";

					default:
						if (Index >= 8 && Index < 16) return "r" + Index;
						else return null;
				}
			}
			else
			{
				return null;
			}
		}

		public static string OpInstruction(x86Operator Op)
		{
			if (Op == x86Operator.IsCarryFlagSet) return "c";
			if (Op == x86Operator.IsCarryFlagZero) return "nc";
			if (Op == x86Operator.IsParityFlagSet) return "p";
			if (Op == x86Operator.IsParityFlagZero) return "np";
			if (Op == x86Operator.IsZeroFlagSet) return "z";
			if (Op == x86Operator.IsZeroFlagZero) return "nz";
			if (Op == x86Operator.IsSignFlagSet) return "s";
			if (Op == x86Operator.IsSignFlagZero) return "ns";
			if (Op == x86Operator.IsOverflowFlagSet) return "o";
			if (Op == x86Operator.IsOverflowFlagZero) return "no";
			return null;
		}

		public static string OpInstruction(Operator Op, bool Signed)
		{
			if (Op == Operator.Equality) return "e";
			if (Op == Operator.Inequality) return "ne";
			if (Op == Operator.Less) return Signed ? "l" : "b";
			if (Op == Operator.LessEqual) return Signed ? "le" : "be";
			if (Op == Operator.Greater) return Signed ? "g" : "a";
			if (Op == Operator.GreaterEqual) return Signed ? "ge" : "ae";
			return null;
		}

		public x86MoveCondBranch GetNodeMoveBranch(ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			if (OpNode == null) return null;

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

			if (Op == Operator.Assignment)
			{
				var To = x86Expressions.GetLocation(this, Ch[0]);
				var From = x86Expressions.GetLocation(this, Ch[1]);
				if (From == null || To == null || x86Expressions.NeedsInstructions(Ch[0]))
					return null;

				if (x86Expressions.NeedsInstructions(Ch[1]))
					return From.Compare(To) ? GetNodeMoveBranch(Ch[1]) : null;

				var Data = Node.Data.Get<x86NodeData>();
				return new x86MoveCondBranch(To, From, Data.TempData, x86ExecutorType.All, Node.Type);
			}
			else if (Op == Operator.Cast)
			{
				var Data = Node.Data.Get<x86NodeData>();
				var To = Expressions.GetIdentifier(Ch[1]);

				var StoredDataType = x86Identifiers.GetStoredDataType(To);
				if (!Ch[0].Type.IsEquivalent(To) || x86Identifiers.IsFloatTypeKind(StoredDataType.TypeKind))
					return null;

				var From = x86Expressions.GetLocation(this, Ch[0]);
				if (From != null && Data.Output != null && !x86Expressions.NeedsInstructions(Ch[0]))
				{
					return new x86MoveCondBranch(Data.ExtractedOutput, From,
						Data.TempData, x86ExecutorType.All, StoredDataType);
				}
			}

			return null;
		}

		public CondBranch GetNodeCondBrach(ExpressionNode Node,
			bool EnableMoveBranch = true, bool RetNull = true)
		{
			if (EnableMoveBranch)
			{
				var Ret = GetNodeMoveBranch(Node);
				if (Ret != null) return Ret;
			}

			if (RetNull) return null;
			return new CodeCondBranch(x => x.EmitExpression(Node));
		}

		public CondBranch GetCondBranchWithMove(x86DataLocation Dst, x86NodeData Data, ExpressionNode Node)
		{
			if (x86Expressions.NeedsInstructions(Node))
			{
				return new CodeCondBranch(CG =>
				{
					var x86CG = CG as x86CodeGenerator;
					x86CG.EmitMoveExpression(Data, Dst, Node);
				});
			}

			var Src = x86Expressions.GetLocation(this, Node);
			return new x86MoveCondBranch(Dst, Src, Data.TempData, x86ExecutorType.All, Node.Type);
		}

		private ExpressionNode GetExpr(Command Obj)
		{
			return Obj != null && Obj.Type == CommandType.Expression ? Obj.Expressions[0] : null;
		}

		void ProcessMoveCondBranch(GlobalContainer Global, x86MoveCondBranch Branch)
		{
			if (Branch.Struct.Dst != null && Branch.Struct.Src is x86ConstLocation &&
				Branch.Struct.Dst.Size > 1 && Branch.Struct.Dst is x86GRegLocation)
			{
				var ConstPos = Branch.Struct.Src as x86ConstLocation;
				var GlbVar = Global.CreateExprConst(ConstPos.Value, ConstPos.Type);
				if (GlbVar == null) throw new ApplicationException();

				var Data = GlbVar.Data.Get<x86IdentifierData>();
				Branch.Struct.Src = Data.Location;
			}
		}

		CondBranch GetJumpBranch(Command Comm)
		{
			if (Comm == null) return null;

			if (Comm.Extension is NCCommandExtension)
			{
				var NCExtension = Comm.Extension as NCCommandExtension;
				if (NCExtension.Type == NCCommandType.Jump)
				{/*
				var Src = Expressions.GetIdentifier(Comm.Expressions[0]);
				if (!(Comm.Expressions[0] is OpExpressionNode))
				{
					return new CodeCondBranch(CG =>
					{
						var x86CG = CG as x86CodeGenerator;
						var SrcLoc = x86Expressions.GetLocation(this, Comm.Expressions[0]);
						x86CG.ProcessIndexMoves(SrcLoc);
						x86CG.Append("\tjmp " + SrcLoc + "\n");
					});
				}*/
				}
			}

			if (Commands.IsJumpCommand(Comm.Type))
			{
				if (Comm.Type != CommandType.Return || Comm.Expressions == null || Comm.Expressions.Count == 0)
					return new JumpCodeBranch(Comm.Label);
			}
			else if (Comm.Type == CommandType.Unknown)
			{
			}

			return null;
		}

		public CondBranch[] GetBranches(GlobalContainer Global, Command Then,
			Command Else, ref ExpressionNode Condition)
		{
			var ThenJump = GetJumpBranch(Then);
			var ElseJump = GetJumpBranch(Else);
			if (ThenJump != null || ElseJump != null)
				return new CondBranch[] { ThenJump, ElseJump };

			var OpCond = Condition as OpExpressionNode;
			if (OpCond != null && !Operators.IsRelEquality(OpCond.Operator))
				return new CondBranch[] { null, null };

			var ExprElse = GetNodeCondBrach(GetExpr(Else));
			var ExprThen = GetNodeCondBrach(GetExpr(Then));
			var MoveElse = ExprElse as x86MoveCondBranch;
			var MoveThen = ExprThen as x86MoveCondBranch;

			if (MoveThen != null && ExprElse != null && MoveThen.Struct.Dst.Compare(MoveElse.Struct.Dst))
			{
				if (MoveThen.Struct.Src is x86ConstLocation && !(MoveElse.Struct.Src is x86ConstLocation))
				{
					if (OpCond != null)
					{
						OpCond.Operator = Operators.Negate(OpCond.Operator);
					}
					else
					{
						var False = Constants.GetBoolValue(Global, false, new CodeString());
						var Ch = new ExpressionNode[] {OpCond, False };
						OpCond = new OpExpressionNode(Operator.Equality, Ch, OpCond.Code);
					}

					return new CondBranch[] { ExprElse, ExprThen };
				}
				else
				{
					ProcessMoveCondBranch(Global, MoveThen);
				}
			}
			else if (MoveThen != null && Else == null)
			{
				ProcessMoveCondBranch(Global, MoveThen);
			}

			return new CondBranch[] { ExprThen, ExprElse };
		}

		public ExpressionNode OverflowCondition(PluginRoot Plugin, ExpressionNode Node, 
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Both)
		{
			var Type = Node.Type.RealId as Type;
			var Signed = Type is SignedType;

			if ((BEMode & BeginEndMode.Begin) != 0 && !Plugin.Begin())
				return null;

			ExpressionNode Ret = new OpExpressionNode(Operator.Unknown, null, Code);
			Ret.Type = Plugin.Container.GlobalContainer.CommonIds.Boolean;

			var Op = Signed ? x86Operator.IsOverflowFlagSet : x86Operator.IsCarryFlagSet;
			Ret.Data.Create<x86NodeData>().Operator = Op;

			if (Plugin.NewNode(ref Ret) == PluginResult.Failed) return null;
			if ((BEMode & BeginEndMode.End) != 0 && Plugin.End(ref Ret) == PluginResult.Failed)
				return null;

			return Ret;
		}
	}
}

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