public void Compile( If statement, ICompilationContext context ) { var preferredRegisterCondition = new PreferredRegister(Register64.RAX); var ifConditionResult = context.CompileExpression(statement.Condition, preferredRegisterCondition); ifConditionResult.GenerateMoveTo(preferredRegisterCondition.MakeFor(Constants.BoolType), context.Generator, context.Linking); context.Generator.Test(Register8.AL, Register8.AL); var ifBody = context.CreateChildContext(); var elseBody = context.CreateChildContext(); if (statement.ElseInstruction != null) { elseBody.CompileStatement(statement.ElseInstruction.StatementAsBlock()); } ifBody.CompileStatement(statement.Instruction.StatementAsBlock()); var elseBodySpan = elseBody.Generator.GetBufferSpan(); if (elseBodySpan.Length > 0) { if (elseBodySpan.Length <= sbyte.MaxValue) { ifBody.Generator.Jmp((sbyte)elseBodySpan.Length); } else { ifBody.Generator.Jmp(elseBodySpan.Length); } } var ifBodySpan = ifBody.Generator.GetBufferSpan(); if (ifBodySpan.Length <= sbyte.MaxValue) { context.Generator.Je((sbyte)ifBodySpan.Length); } else { context.Generator.Je(ifBodySpan.Length); } ifBody.CopyToContext(context); elseBody.CopyToContext(context); }
public void Compile( While statement, ICompilationContext context ) { var codeGen = context.Generator; var conditionStart = codeGen.StreamPosition; var whileConditionResult = context.CompileExpression(statement.Condition, new PreferredRegister(Register64.RAX)); var whileConditionRegister = whileConditionResult.GetOccupiedOrVolatile(Constants.BoolType); whileConditionResult.GenerateMoveTo(whileConditionRegister, Constants.BoolType, codeGen, context.Linking); codeGen.Test(whileConditionRegister, whileConditionRegister); var childContext = context.CreateChildContext(); childContext.CompileStatement(statement.Instruction.StatementAsBlock()); var bodySpan = childContext.Generator.GetBufferSpan(); var bodyLength = bodySpan.Length + JmpIntSize; // assume far jmp will be generated if (bodyLength <= sbyte.MaxValue) { codeGen.Je((sbyte)bodyLength); } else { codeGen.Je(bodyLength); } var farJmpGuessPos = codeGen.StreamPosition; childContext.CopyToContext(context); var offsetToStart = conditionStart - codeGen.StreamPosition; if (offsetToStart >= sbyte.MinValue) { codeGen.Jmp((sbyte)(offsetToStart - JmpSbyteSize)); // near jmp has been generated, but we assume a far jmp above // if this is a near jmp, the other has to be too // so it's safe to say, we just need to edit the byte. // The new value has to fit, because the jmp becomes even nearer. codeGen.GetBufferSpan().Slice((int)farJmpGuessPos - 1, 1)[0] -= (byte)(JmpIntSize - JmpSbyteSize); } else { codeGen.Jmp((int)(offsetToStart - JmpIntSize)); } }