private static void DeleteUnusedRegisters(ByteCode byteCode, FunctionInstructions function) { var toDelete = new List <int>(); foreach (var register in function.Registers) { if (!VariableUsed(register.Index, 0, function)) { toDelete.Add(register.Index); } } foreach (var variable in toDelete) { function.Registers.RemoveAll(p => p.Index == variable); } toDelete.Clear(); foreach (var local in function.Locals) { if (!VariableUsed(local.Index, 0, function)) { toDelete.Add(local.Index); } } foreach (var variable in toDelete) { function.Locals.RemoveAll(p => p.Index == variable); } }
private static bool VariableUsed(int registerIndex, int startIndex, FunctionInstructions function) { for (var i = startIndex; i < function.Instructions.Count; i++) { if (function.Instructions[i].UsesVariable(registerIndex)) { return(true); } } return(false); }
private static bool VariableUsedBefore(int registerIndex, int startIndex, FunctionInstructions function) { for (var i = startIndex; i >= 0; i--) { if (function.Instructions[i].UsesVariable(registerIndex)) { return(true); } } return(false); }
private void ExpressionToList( ExpressionLexeme expression, Lexeme lexeme, Function function, out Variable resultVar, ref int labelIndex, ref int localVarIndex, ref int regCount, List <Variable> outRegisters, FunctionInstructions instructionsSet, List <NumeratedVariable> locals, Variable storeResultTo) { ExpressionToList_GetList(expression, lexeme, function, out resultVar, ref labelIndex, ref localVarIndex, ref regCount, outRegisters, instructionsSet, locals, storeResultTo); ExpressionToList_FixIndexerAssignment(expression, lexeme, function, ref labelIndex, ref localVarIndex, ref regCount, outRegisters, instructionsSet, locals, storeResultTo); ExpressionToList_IndexerMultiply(function, ref labelIndex, instructionsSet); }
private static void ReplaceAllUsages(FunctionInstructions function, int startIndex, int oldIndex, int newIndex) { for (var i = startIndex; i < function.Instructions.Count; i++) { function.Instructions[i].ReplaceRegisterUsage(oldIndex, newIndex); /*var usedVariables = instruction.FetchUsedVariables(oldIndex); * if (usedVariables.Count != 0) * { * //usedVariables.ForEach(p => p.Index = newIndex); * }*/ } }
private static void FixRegistersIndexes(ByteCode byteCode, FunctionInstructions function) { var index = function.Locals.Count + byteCode.Program.ProgramGlobals.Count; foreach (var register in function.Registers) { foreach (var instruction in function.Instructions) { instruction.ReplaceRegisterUsage(register.Index, index); } register.Index = index; index++; } }
private static List <Variable> GetFreeRegisters(int startIndex, FunctionInstructions function) { var freeRegisters = new List <Variable>(); foreach (var register in function.Registers) { if (!VariableUsed(register.Index, startIndex, function)) { freeRegisters.Add(register); } } return(freeRegisters); }
private static void OptimizeRegisters(ByteCode byteCode, FunctionInstructions function) { var freeRegisters = GetFreeRegistersList(function); for (var i = 0; i < freeRegisters.Length; i++) { //Some registers are free if (freeRegisters[i] != function.Registers.Count) { var usedVariables = function.Instructions[i].FetchUsedVariables(-1); //uses at least one variable if (usedVariables.Count == 0) { continue; } var usedRegisters = usedVariables.FindAll(p => p.Index >= function.Locals.Count + byteCode.Program.ProgramGlobals.Count); //uses at least one register if (usedRegisters.Count == 0) { continue; } var unusedRegisters = GetFreeRegisters(i, function); foreach (var unusedRegister in unusedRegisters) { var replaceableRegister = usedRegisters .Find(p => p.Type == unusedRegister.Type && !VariableUsedBefore(p.Index, i - 1, function)); if (replaceableRegister != null) { //Can be replaced ReplaceAllUsages(function, i, replaceableRegister.Index, unusedRegister.Index); //update list and start again freeRegisters = GetFreeRegistersList(function); i = 0; function.Registers.RemoveAll(p => p.Index == replaceableRegister.Index); } } } } }
private static int[] GetFreeRegistersList(FunctionInstructions function) { var freeRegisters = new int[function.Instructions.Count]; for (var i = 0; i < freeRegisters.Length; i++) { foreach (var register in function.Registers) { if (VariableUsed(register.Index, i, function)) { freeRegisters[i] += 1; } } } return(freeRegisters); }
private static void OptimizePopPushCase(ByteCode byteCode, FunctionInstructions function) { for (int i = 0; i < function.Instructions.Count - 1; i++) { //has PUSH after POP if (function.Instructions[i].Type == InstructionType.Pop && function.Instructions[i + 1].Type == InstructionType.Push) { //both have same index if ((function.Instructions[i] as InstructionPop).Result.Index == (function.Instructions[i + 1] as InstructionPush).Variable.Index) { function.Instructions.RemoveAt(i + 1); function.Instructions.RemoveAt(i); i -= 1; } } } }
private void GetInstructionList(Lexeme rootLexeme, Function function, ref int localVarIndex, ref int regCount, ref int labelIndex, List <Variable> registers, FunctionInstructions instructionsSet, List <NumeratedVariable> locals) { foreach (var lexeme in rootLexeme.ChildLexemes) { //localVarIndex = locals.Count; switch (lexeme.Type) { case LexemeType.Block: break; case LexemeType.Var: { //Calculate expression var expression = ((VarLexeme)lexeme).Expression; //declaration only if (expression == null) { continue; } var storeResult = locals.Find(p => p.Index == ((VarLexeme)lexeme).Index + Program.ProgramGlobals.Count).Variable; Variable variable; ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount, registers, instructionsSet, locals, storeResult); } break; case LexemeType.If: { var ifLexeme = lexeme as IfLexeme; //Calculate expression var expression = ((IfLexeme)lexeme).Expression; Variable variable; ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount, registers, instructionsSet, locals, null); if (variable == null) { throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]); } instructionsSet.Instructions.Add(new InstructionBrEq(variable, -1, function, this, labelIndex++)); var eq = instructionsSet.Instructions.Last() as InstructionBrEq; //Proceed block GetInstructionList(ifLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex, registers, instructionsSet, locals); if (ifLexeme.ElseLexeme != null) { instructionsSet.Instructions.Add(new InstructionJmp(-1, function, this, labelIndex++)); var jmp = instructionsSet.Instructions.Last() as InstructionJmp; eq.Index = labelIndex; //Proceed else block GetInstructionList(ifLexeme.ElseLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex, registers, instructionsSet, locals); jmp.Index = labelIndex; } else { eq.Index = labelIndex; } } break; case LexemeType.Expression: { //Calculate expression Variable variable; ExpressionToList((ExpressionLexeme)lexeme, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount, registers, instructionsSet, locals, null); } break; case LexemeType.While: { var whileLexeme = lexeme as WhileLexeme; int startIndex = labelIndex; //Calculate expression var expression = whileLexeme.Expression; Variable variable; ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount, registers, instructionsSet, locals, null); if (variable == null) { throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]); } instructionsSet.Instructions.Add(new InstructionBrEq(variable, -1, function, this, labelIndex++)); var eq = instructionsSet.Instructions.Last() as InstructionBrEq; //Proceed block GetInstructionList(whileLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex, registers, instructionsSet, locals); instructionsSet.Instructions.Add( new InstructionJmp(startIndex, function, this, labelIndex++)); eq.Index = labelIndex; } break; case LexemeType.Return: { //Calculate expression Variable variable; ExpressionToList(((ReturnLexeme)lexeme).Expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount, registers, instructionsSet, locals, null); if (variable.Type != function.ReturnType) { //but can we cast? if (!Type.CanCastAssignment(function.ReturnType, variable.Type)) { throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[1]); } //casting var castedVar = new Variable(function.ReturnType, "__castedReg", function.Scope, null, localVarIndex++, VariableType.Variable); instructionsSet.Instructions.Add(new InstructionCast(castedVar, variable, function, this, labelIndex++)); variable = castedVar; registers.Add(castedVar); } instructionsSet.Instructions.Add(new InstructionPush(variable, function, this, labelIndex++)); } break; } } }
private void ExpressionToList_GetList( ExpressionLexeme expression, Lexeme lexeme, Function function, out Variable resultVar, ref int labelIndex, ref int localVarIndex, ref int regCount, List <Variable> outRegisters, FunctionInstructions instructionsSet, List <NumeratedVariable> locals, Variable storeResultTo) { var list = expression.ToList(); var labelIndexCopy = labelIndex; if (list == null) { if (expression.Root.SubTokens.Count == 1) { ExpressionToken token = expression.Root.SubTokens[0]; Variable src = ExpressionLineItem.GetVariable(locals, this, token.CodeToken); if (token.UnaryOperators.Count != 0 && token.UnaryOperators[0] != null) { var unaryRes = token.UnaryOperators[0].UnaryFunc(new OperatorOperands(function, this, labelIndexCopy++, src)); if (unaryRes.Error != null) { throw new CompileException(unaryRes.Error.ErrorType, token.CodeToken); } instructionsSet.Instructions.Add(unaryRes.Instruction); if (storeResultTo != null) { var lastInstruction = (UnaryArithmeticInstruction)unaryRes.Instruction; if (unaryRes.ResultType != storeResultTo.Type) { //but can we cast? if (!Type.CanCastAssignment(storeResultTo.Type, unaryRes.ResultType)) { throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]); } var castedVar = new Variable(unaryRes.ResultType, "__unaryReg", function.Scope, null, localVarIndex++, VariableType.Variable); instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, castedVar, function, this, labelIndexCopy++)); lastInstruction.Result = castedVar; outRegisters.Add(castedVar); } else { lastInstruction.Result = storeResultTo; } resultVar = storeResultTo; } else { resultVar = (unaryRes.Instruction as UnaryArithmeticInstruction).Result; } } else { if (storeResultTo != null) { if (storeResultTo.Type != src.Type) { //Not equal, cast is needed. if (!Type.CanCastAssignment(storeResultTo.Type, src.Type)) { throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]); } instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, src, function, this, labelIndexCopy++)); resultVar = storeResultTo; } else { instructionsSet.Instructions.Add(new InstructionLdi(src, storeResultTo, function, this, labelIndexCopy++)); resultVar = storeResultTo; } } else { resultVar = src; } } } else { throw new CompileException(CompileErrorType.WrongOperandList, lexeme.Tokens[0]); } } else { if (function.Program.Verbose) { Console.WriteLine(string.Join("\n", list)); } List <Variable> registers; var res = ExpressionLineItem.GetInstructions(function, this, ref localVarIndex, list, out registers, locals); if ( (res.Last() is BinaryArithmeticInstruction) && ((BinaryArithmeticInstruction)res.Last()).CanBeSimplified() && (res.Count < 2 || res[res.Count - 2].Type != InstructionType.Vget || (res.Last() as BinaryArithmeticInstruction).Operand1.VariableType != VariableType.ArrayItem)) { var last = (BinaryArithmeticInstruction)res.Last(); if (last.AType == BinaryArithmeticInstructionType.A_Set && res.Count != 1) { res.RemoveAt(res.Count - 1); (res[res.Count - 1] as ArithmeticInstruction).Result = last.Operand1; } else { res[res.Count - 1] = last.Simplify(); } registers.RemoveAt(registers.Count - 1); } regCount += registers.Count; outRegisters.AddRange(registers); res.ForEach(p => p.Label = labelIndexCopy++); instructionsSet.Instructions.AddRange(res); if (storeResultTo != null) { if (!(instructionsSet.Instructions.Last() is ArithmeticInstruction)) { throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]); } var lastInstruction = (ArithmeticInstruction)instructionsSet.Instructions.Last(); if (lastInstruction.Result.Type != storeResultTo.Type) { //but can we cast? if (!Type.CanCastAssignment(storeResultTo.Type, lastInstruction.Result.Type)) { throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]); } instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, lastInstruction.Result, function, this, labelIndexCopy++)); } else { lastInstruction.Result = storeResultTo; } resultVar = storeResultTo; } else { var last = instructionsSet.Instructions.Last(); if (!(last is ArithmeticInstruction)) { resultVar = null; } else { resultVar = (last as ArithmeticInstruction).Result; } } } labelIndex = labelIndexCopy; }
private void ExpressionToList_FixIndexerAssignment( ExpressionLexeme expression, Lexeme lexeme, Function function, ref int labelIndex, ref int localVarIndex, ref int regCount, List <Variable> outRegisters, FunctionInstructions instructionsSet, List <NumeratedVariable> locals, Variable storeResultTo) { //find assignment to array elements and replace it by vset and remove first vget for (int i = 0; i < instructionsSet.Instructions.Count; i++) { Variable result = null; var simplified = false; var set = false; if (instructionsSet.Instructions[i] is ArithmeticInstruction && !(instructionsSet.Instructions[i] is InstructionVget)) { if (instructionsSet.Instructions[i] is BinaryArithmeticInstruction && (instructionsSet.Instructions[i] as BinaryArithmeticInstruction).CanBeSimplified()) { var instruction = ((BinaryArithmeticInstruction)instructionsSet.Instructions[i]); result = instruction.Operand1; simplified = true; if (instruction.AType == BinaryArithmeticInstructionType.A_Set) { set = true; } } else { result = ((ArithmeticInstruction)instructionsSet.Instructions[i]).Result; } } else { continue; } InstructionVset vset; if (result.VariableType == VariableType.ArrayItem) { if (!simplified) { var newReg = new Variable(result.Type, "__arrayReg", function.Scope, result.Token, localVarIndex++, VariableType.Variable); vset = new InstructionVset( result.Array, newReg, result.ArrayItem, function, this, labelIndex++); outRegisters.Add(newReg); instructionsSet.Instructions.Insert(i + 1, vset); var globalIndex = 0; var deleted = instructionsSet.Instructions.RemoveAll(p => { var vget = p as InstructionVget; if (vget == null) { return(false); } var used = false; for (var j = globalIndex + 1; j < instructionsSet.Instructions.Count; j++) { var count = instructionsSet.Instructions[j].FetchUsedVariables(vget.Result.Index).Count; count -= (instructionsSet.Instructions[j] as ArithmeticInstruction)?.Result.Index == vget.Result.Index ? 1 : 0; if (count > 0) { used = true; break; } } globalIndex++; return(vget.Result.Index == result.Index && !used); }); (instructionsSet.Instructions[i - deleted] as ArithmeticInstruction).Result = newReg; } else { if (!set) { instructionsSet.Instructions[i] = ((BinaryArithmeticInstruction)instructionsSet.Instructions[i]).Simplify(); vset = new InstructionVset( result.Array, (instructionsSet.Instructions[i] as ArithmeticInstruction).Result, result.ArrayItem, function, this, labelIndex++); instructionsSet.Instructions.Insert(i + 1, vset); } else { vset = new InstructionVset( result.Array, result, result.ArrayItem, function, this, labelIndex++); instructionsSet.Instructions.Insert(i + 1, vset); instructionsSet.Instructions.RemoveAt(i); instructionsSet.Instructions.RemoveAll(p => { var vget = p as InstructionVget; return(vget != null && vget.Result.Index == result.Index); }); } } } } }
public void EmbedFunction(FunctionInstructions function, Token nearToken) { EmbeddedFunctions.Add(function); function.Function.Index = Program.Functions.Count + EmbeddedFunctions.Count - 1; function.Function.Name = $"_{function.Function.Program.Module.Name}_{function.Function.Name}"; //merging types from locals foreach (var local in function.Locals) { if (GetTypeIndex(local.Type) == -1) { UsedTypes.Add(new NumeratedType(UsedTypes.Count, local.Type)); } } //merging types from constants foreach (var instruction in function.Instructions) { var locals = instruction.FetchUsedVariables(-2); foreach (var local in locals) { if (local.VariableType == VariableType.LinkToConst) { var constant = function.Function.Program.ByteCode.Header. UsedConstants[local.ConstIndex].Constant; if (GetTypeIndex(constant.ToProgramType()) == -1) { UsedTypes.Add(new NumeratedType(UsedTypes.Count, constant.ToProgramType())); } int index; if ((index = GetConstIndex(constant)) == -1) { index = UsedConstants.Count; UsedConstants.Add(new NumeratedConstant(index, constant)); } local.ConstIndex = index; } else { //is global if (local.IndexFixed) { continue; } if (instruction.Function.Program.ProgramGlobals.Contains(local)) { local.Index = Program.ProgramGlobals.IndexOf(local); } else { local.Index = local.Index - function.Function.Program.ProgramGlobals.Count + Program.ProgramGlobals.Count; } local.IndexFixed = true; } } if (instruction.Type == InstructionType.Call) { var call = instruction as InstructionCall; var func = call.DestFunc; var newFunction = function.Function.Program.ByteCode.Instructions.Find(p => p.Function == func); //recursive call if (newFunction == function) { continue; } if (newFunction == null) { throw new ArgumentNullException(nameof(newFunction)); } if (EmbeddedFunctions.Any(p => p.Function == func)) { continue; //already embedded } if (newFunction.Function.Modifier == FunctionModifier.Finalization || newFunction.Function.Modifier == FunctionModifier.Initialization) { throw new CompileException(CompileErrorType.ModuleFunctionCall, nearToken, newFunction.Function.Token); } EmbedFunction(newFunction, nearToken); call.DestFunc = newFunction.Function; } } }
private void ExpressionToList_IndexerMultiply(Function function, ref int labelIndex, FunctionInstructions instructionsSet) { //when all indices were collected, we just replace it by product of them for (int i = 0; i < instructionsSet.Instructions.Count; i++) { if (instructionsSet.Instructions[i].Type == InstructionType.Vget || instructionsSet.Instructions[i].Type == InstructionType.Vset) { List <Variable> indexes; Variable array; if (instructionsSet.Instructions[i].Type == InstructionType.Vget) { var vget = instructionsSet.Instructions[i] as InstructionVget; indexes = vget._indices; array = vget._array; if (vget.Expanded) { continue; } vget.Expanded = true; } else { var vset = instructionsSet.Instructions[i] as InstructionVset; indexes = vset._indices; array = vset._array; if (vset.Expanded) { continue; } vset.Expanded = true; } var newInstructions = new List <Instruction>(); newInstructions.Add(new InstructionVect(array, function, this, labelIndex++)); foreach (var index in indexes) { newInstructions.Add(new InstructionVind(index, function, this, labelIndex++)); } instructionsSet.Instructions.InsertRange(i, newInstructions); i += newInstructions.Count; } } }
public void Proceed() { //embed all module init and fin functions List <FunctionInstructions> inits = null; List <FunctionInstructions> fins = null; if (Program.EntrypointFunction != null) { //embed module globals Program.ProgramGlobals.AddRange(GetModuleGlobals(Program)); inits = GetModuleFunctions(Program, true); fins = GetModuleFunctions(Program, false); foreach (var function in inits) { Header.EmbedFunction(function, function.Function.Token); } foreach (var function in fins) { Header.EmbedFunction(function, function.Function.Token); } } Instructions = new List <FunctionInstructions>(); foreach (var function in Program.Functions) { var labelIndex = 0; var instructionSet = new FunctionInstructions(function); //link inits /*if (function.Modifier == FunctionModifier.Entrypoint) * foreach (var initFunction in inits) * instructionSet.Instructions.Add( * new InstructionCall(initFunction.Function, function, this, labelIndex));*/ var localVarIndex = Program.ProgramGlobals.Count; var locals = function.LocalVariables.Select(p => new NumeratedVariable(localVarIndex++, p)).ToList(); if (function.Parameters.Count != 0) { var parameters = function.Parameters.Select(p => new Variable(p.Type, p.Name, function.Scope, p.CodeToken, localVarIndex++, VariableType.Variable)); locals.AddRange(parameters.Select(p => new NumeratedVariable(p.Index, p))); } foreach (var local in locals) { local.Variable.Index = local.Index; //instructionSet.Instructions.Add(new InstructionLocal(local, function, this, labelIndex++)); } if (function.Parameters.Count != 0) { foreach (var param in locals.Skip(function.LocalVariables.Count)) { instructionSet.Instructions.Add(new InstructionPop(param.Variable, function, this, labelIndex++)); } } var registers = new List <Variable>(); var regCount = 0; //begin syscalls, variadic attributes foreach (var attribute in function.Attributes) { switch (attribute.Type) { case AttributeType.Syscall: if (!((SyscallAttribute)attribute).AppendToEnd) { instructionSet.Instructions.Add(new InstructionSyscall((attribute as SyscallAttribute).CallCode, function, this, labelIndex++)); } break; case AttributeType.Variadic: function.IsVariadic = true; break; } } GetInstructionList(function.RawLexeme, function, ref localVarIndex, ref regCount, ref labelIndex, registers, instructionSet, locals); //link fins /* if (function.Modifier == FunctionModifier.Entrypoint) * foreach (var initFunction in fins) * instructionSet.Instructions.Add( * new InstructionCall(initFunction.Function, function, this, labelIndex));*/ //end syscalls foreach (var attribute in function.Attributes.FindAll(p => p is SyscallAttribute && ((SyscallAttribute)p).AppendToEnd)) { instructionSet.Instructions.Add(new InstructionSyscall((attribute as SyscallAttribute).CallCode, function, this, labelIndex++)); } instructionSet.Instructions.Add(new InstructionRet(function, this, labelIndex++)); instructionSet.Registers = registers; instructionSet.Locals = locals.Select(p => p.Variable).ToList(); Instructions.Add(instructionSet); } Instructions.AddRange(Header.EmbeddedFunctions); Program.Functions.AddRange(Header.EmbeddedFunctions.Select(p => p.Function)); }
private static void DeleteDuplicatedRegisters(ByteCode byteCode, FunctionInstructions function) { function.Registers = function.Registers.GroupBy(p => p.Index).Select(p => p.ToList()[0]).ToList(); }