public AsmCode(PascalProgram program) { GenerateSubprogramHeader(program.Block); var mainLabel = new AsmLabel("main"); Add(mainLabel); program.Block.Generate(this); Add(new AsmSpecial("exit")); GenerateSubprograms(program.Block); Add(new AsmSpecial($"END {mainLabel.ToArgString()}")); }
private AsmLabel PushParams(FieldInfo l, FieldInfo r, LoadClasses load, out AsmLabel trueLabel, out AsmLabel returnLabel) { trueLabel = new AsmLabel("{asm3}"); returnLabel = new AsmLabel("{ret}" + CPUUInt.u); pushParam(load, l.Handle, true, IsSigned(l.Return), l.Return == Assembly.Long); if (r.Return != Assembly.Long) { pushParam(load, r.Handle, false, IsSigned(r.Return), false); } return(new AsmLabel("{asm1}")); }
public override void Generate(AsmCode asmCode, SymTable symTable) { long id = asmCode.CurrentID++; StartLabel = new AsmLabel($"Cycle{id}Start"); EndLabel = new AsmLabel($"Cycle{id}End"); AsmLabel bodyLabel = new AsmLabel($"Cycle{id}Body"); var v = (VarSymbol)symTable.LookUp(Childs[0].Value.ToString()); Childs[1].Generate(asmCode, symTable); // Initial value ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable); // Cycle counter asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Ebx); asmCode.Add(AsmCmd.Cmd.Sub, AsmReg.Reg.Ebx, 1); asmCode.Add( AsmCmd.Cmd.Mov, new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax), AsmReg.Reg.Ebx); // Value initialized asmCode.Add(AsmCmd.Cmd.Jmp, StartLabel); asmCode.Add(bodyLabel); asmCode.LoopStack.Push(this); Childs[3].Generate(asmCode, symTable); // Cycle body asmCode.LoopStack.Pop(); asmCode.Add(StartLabel); ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add(AsmCmd.Cmd.Inc, new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax)); Childs[2].Generate(asmCode, symTable); // Cycle counter target ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add( AsmCmd.Cmd.Mov, AsmReg.Reg.Eax, new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax)); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Ebx); asmCode.Add(AsmCmd.Cmd.Cmp, AsmReg.Reg.Eax, AsmReg.Reg.Ebx); asmCode.Add(AsmCmd.Cmd.Jle, bodyLabel); asmCode.Add(EndLabel); }
private static void Return(FieldInfo ret, LoadClasses load, AsmLabel returnTrue, AsmLabel returnFalse, AsmLabel @return, bool OrEqual) { //Return True load.Optimum.SetLabel(returnTrue); load.Add("mov", RegInfo.eax, ConstInfo.True); //Return False load.Optimum.SetLabel(returnFalse); load.Add("xor", RegInfo.eax, RegInfo.eax); load.Optimum.SetGoto("jmp", @return); //Return load.Optimum.SetLabel(@return); if (OrEqual) { load.Add("test", RegInfo.eax, RegInfo.eax); load.Add("sete", RegInfo.eax); } load.Add("mov", ret, RegInfo.eax); }
public override void Generate(AsmCode asmCode, SymTable symTable) { long id = asmCode.CurrentID++; StartLabel = new AsmLabel($"Cycle{id}Start"); EndLabel = new AsmLabel($"Cycle{id}End"); asmCode.Add(StartLabel); asmCode.LoopStack.Push(this); foreach (var child in Childs) { child.Generate(asmCode, symTable); } asmCode.LoopStack.Pop(); Condition.Generate(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add(AsmCmd.Cmd.Cmp, AsmReg.Reg.Eax, 0); asmCode.Add(AsmCmd.Cmd.Je, StartLabel); asmCode.Add(EndLabel); }
public override void Generate(AsmCode asmCode, SymTable symTable) { long id = asmCode.CurrentID++; var elseLabel = new AsmLabel($"Condtion{id}Else"); var endLabel = new AsmLabel($"Condtion{id}End"); Childs[0].Generate(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add(AsmCmd.Cmd.Cmp, AsmReg.Reg.Eax, 0); asmCode.Add(AsmCmd.Cmd.Je, elseLabel); Childs[1].Generate(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Jmp, endLabel); asmCode.Add(elseLabel); if (Childs.Count > 2) { Childs[2].Generate(asmCode, symTable); } asmCode.Add(endLabel); }
private static FieldInfo lt_gt(FieldInfo ret, FieldInfo l, FieldInfo r, LoadClasses load, bool is_lt_gt) { string jm1, jm2, jm3; if (is_lt_gt) { jm1 = "jg"; jm2 = "jl"; jm3 = "jb"; } else { jm1 = "jl"; jm2 = "jg"; jm3 = "ja"; } AsmLabel falseLabel = new AsmLabel("{asm1}"), trueLabel = new AsmLabel("{asm3}"), returnLabel = new AsmLabel("{ret}" + CPUUInt.u); var r_islong = r.Return == Assembly.Long; pushParam(load, l.Handle, true, IsSigned(l.Return), l.Return == Assembly.Long); if (!r_islong) { pushParam(load, r.Handle, false, IsSigned(r.Return), false); } load.Add("cmp", Reg.edx, !r_islong ? Reg.ebx : r.GetHandle(4)); load.Optimum.SetGoto(jm1, trueLabel, load, cByte.Clone()); load.Optimum.SetGoto(jm2, falseLabel, load, cByte.Clone()); load.Add("cmp", RegInfo.eax, !r_islong ? RegInfo.ecx : r); load.Optimum.SetGoto(jm3, trueLabel, load, cByte.Clone()); load.Optimum.SetLabel(falseLabel); load.Add("xor", RegInfo.eax, RegInfo.eax); load.Optimum.SetGoto("jmp", returnLabel, load, new Operand(0xFF, DataType.Byte)); load.Optimum.SetLabel(trueLabel); load.Add("mov", Reg.eax, new Operand(1, DataType.Byte)); load.Optimum.SetLabel(returnLabel); load.Add("mov", ret, RegInfo.eax); return(ret); }
public override void Generate(AsmCode asmCode, SymTable symTable) { long id = asmCode.CurrentID++; StartLabel = new AsmLabel($"Cycle{id}Start"); EndLabel = new AsmLabel($"Cycle{id}End"); AsmLabel bodyLabel = new AsmLabel($"Cycle{id}Body"); asmCode.Add(AsmCmd.Cmd.Jmp, StartLabel); asmCode.Add(bodyLabel); asmCode.LoopStack.Push(this); Childs[0].Generate(asmCode, symTable); asmCode.LoopStack.Pop(); asmCode.Add(StartLabel); Condition.Generate(asmCode, symTable); asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); asmCode.Add(AsmCmd.Cmd.Cmp, AsmReg.Reg.Eax, 0); asmCode.Add(AsmCmd.Cmd.Jne, bodyLabel); asmCode.Add(EndLabel); }
private static void FPReturn(FieldInfo ret, LoadClasses load, string cn, AsmLabel returnTrue, AsmLabel returnFalse, AsmLabel @return, bool OrEqual) { load.Add("cmp", RegInfo.eax, RegInfo.ecx); load.Optimum.SetGoto(cn, returnTrue); Return(ret, load, returnTrue, returnFalse, @return, OrEqual); }
private static FieldInfo Compile(FieldInfo ret, FieldInfo l, FieldInfo r, LoadClasses load, string o, AsmLabel returnFalse, string oc, AsmLabel returnTrue, string cn, AsmLabel @return, bool orEqual, bool IsEquality = false) { PushParams(load, l, r); load.Add("cmp", RegInfo.edx, RegInfo.ebx); load.Optimum.SetGoto(o, returnFalse); if (!IsEquality) { load.Optimum.SetGoto(oc, returnTrue); } FPReturn(ret, load, cn, returnTrue, returnFalse, @return, orEqual); return(ret); }
protected override FieldInfo BeginCompile(MethodInfo method, FieldInfo ret, FieldInfo l, FieldInfo r, LoadClasses load, Scop scop) { var lsigned = IsSigned(l); var rsigned = IsSigned(r); var returnTrue = new AsmLabel("{lasm" + u++ + "}"); var returnFalse = new AsmLabel("{lasm" + u++ + "}"); var @return = new AsmLabel("{lasm" + u++ + "}"); string o = "", oc = ""; var cnc = ""; switch (method.Name) { #region +-&^| case "opers": return(UintSOperation(ret, l, r, load, o, oc)); case "+": o = "add"; oc = "adc"; goto case "opers"; case "-": o = "sub"; oc = "sbb"; goto case "opers"; case "&": oc = o = "and"; goto case "opers"; case "^": oc = o = "xor"; goto case "opers"; case "|": oc = o = "or"; goto case "opers"; #endregion #region */ case "*": o = "imul"; goto case "*/"; case "/": o = "idiv"; goto case "*/"; case "*/": if (lsigned == rsigned) { load.Add(o, l, r); load.Add("mov", ret, RegInfo.eax); return(ret); } if (lsigned) { CallManager.swap(ref l, ref r); } ConvertToLong(load, l, true); load.Add("push", RegInfo.edx); load.Add("push", RegInfo.eax); ConvertToLong(load, r, true); load.Add("push", RegInfo.edx); load.Add("push", RegInfo.eax); load.Optimum.Call(method); Move(load, ret, Reg.eax, Reg.eax); break; #endregion #region none case ">>": break; case "<<": break; case "++": case "--": load.Add("mov", RegInfo.eax, l); load.Add(method.Name == "++" ? "inc" : "dec", RegInfo.eax); load.Add("mov", l, RegInfo.eax); return(ret); #endregion #region == != case "==!=": if (lsigned != rsigned) { return(Compile(ret, l, r, load, o, returnFalse, oc, returnTrue, "je", @return, false, true)); } load.Add("mov", RegInfo.eax, l); load.Add("cmp", RegInfo.eax, r); load.Add(cnc, RegInfo.eax); load.Add("mov", ret, RegInfo.eax); return(ret); case "==": cnc = "sete"; o = "jne"; goto case "==!="; case "!=": o = "je"; cnc = "setne"; goto case "==!="; #endregion #region <==> case ">=": cnc = "sete"; if (lsigned != rsigned) { return(Compile(ret, l, r, load, "jg", returnFalse, "jl", returnTrue, "jb", @return, true)); } goto case "<==>"; case "<==>": load.Add("mov", RegInfo.eax, l); load.Add("cmp", RegInfo.eax, r); if (cnc == "sete") { load.Add("sbb", RegInfo.eax, RegInfo.eax); } load.Add(cnc, RegInfo.eax); load.Add("mov", ret, RegInfo.eax); break; case "<=": cnc = "setbe"; if (lsigned != rsigned) { return(Compile(ret, l, r, load, "jl", returnFalse, "jb", returnTrue, "ja", @return, true)); } goto case "<==>"; #endregion case ">": #region > if (lsigned == rsigned) { load.Add("mov", RegInfo.eax, l); load.Add("cmp", RegInfo.eax, r); load.Add("seta", RegInfo.eax); load.Add("mov", ret, RegInfo.eax); return(ret); } return(Compile(ret, l, r, load, "jl", returnFalse, "jg", returnTrue, "ja", @return, false)); #endregion case "<": #region > if (lsigned == rsigned) { load.Add("mov", RegInfo.eax, l); load.Add("cmp", RegInfo.eax, r); load.Add("sbb", RegInfo.eax, RegInfo.eax); load.Add("neg", RegInfo.eax); load.Add("mov", ret, RegInfo.eax); return(ret); } return(Compile(ret, l, r, load, "jg", returnFalse, "jl", returnTrue, "jb", @return, false)); #endregion } return(ret); }
private void RunJumpTestProgram(OpCode aOp, JumpType aType, bool aInvert, bool aUseLabel) { const Registers ac = Registers.AC; const Registers r1 = Registers.R1; const Registers r2 = Registers.R2; var expected = aInvert ? 0x321 : 0x123; var program = new List <CompilerIns> { // Set the accumulator to be zero. // This isn't strictly required as it // will default to zero, but just to be // safe. new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0, ac }) }; // Calculate the value required value to ensure // that the jump condition is or isn't taken. var value = aType switch { JumpType.EQ => aInvert ? 1 : 0, JumpType.NEQ => aInvert ? 0 : 1, JumpType.LT => aInvert ? 1 : -1, JumpType.GT => aInvert ? -1 : 1, JumpType.LTE => aInvert ? 2 : -2, JumpType.GTE => aInvert ? -2 : 2, _ => 0 }; object arg; var argTypes = _instructionCache[aOp].ArgumentTypes; if (argTypes[0] == typeof(Registers)) { // Set the register to the required value. program.Add ( new CompilerIns(OpCode.MOV_LIT_REG, new object[] { value, r1 }) ); // This will become the jump instruction // condition argument below. arg = r1; } else { // This will become the jump instruction // condition argument below. arg = value; } var labels = new AsmLabel[2]; if (aUseLabel) { labels[1] = new AsmLabel("GOOD", 1); } // If we are not using labels then we will go back and // update the jump position below. // Insert a placeholder value here for the time being. program.Add ( new CompilerIns(aOp, new [] { arg, 0 }, labels) ); // In the jump not taken (inverted) case // this should execute. program.Add ( new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0x321, r2 }) ); // Add a halt instruction to block execution // of the success instruction. program.Add(new CompilerIns(OpCode.HLT)); if (aUseLabel) { program.Add ( new CompilerIns(OpCode.LABEL, new object[] { "GOOD" }) ); } else { // Calculate the address of the current instruction. // This effectively acts as a label. var jumpAddress = CalculateDestinationAddress(program); // Go back and update the jump address in the instruction // from which the jump should or shouldn't occur. foreach (var entry in program) { if (entry.Op != aOp) { continue; } entry.Args[1] = jumpAddress; break; } } // In the jump is taken (normal) case this should execute. program.Add ( new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0x123, r2 }) ); // Run the test program. Vm.Run(QuickCompile.RawCompile(program.ToArray())); // Check the result. Assert.IsTrue ( Vm.Cpu.Registers[r2] == expected, $"Test OpCode '{aOp}'. " + $"Inverted = {aInvert}, Use Label = {aUseLabel} failed " + "to yield the correct result." ); }
public void Add(AsmCmd.Cmd cmd, AsmLabel label) { Add(new AsmJump(cmd, label)); }
public AsmGoto(int gotoLocation, AsmLabel label) { GotoLocation = gotoLocation; Label = label; }