private static ExpressionResult CompileModolu( IExpression left, IExpression right, PreferredRegister target, ICompilationContext context ) { var leftRegisterPref = new PreferredRegister(Register64.RAX, target.FloatRegister); var(leftReg, rightExpr, type) = PrepareBinaryExpression( left, right, leftRegisterPref, context, true ); if (type.IsIntegerRegisterType()) { var typeIsByte = CompileIntegerDivision(context.Generator, context.Linking, type, leftReg, rightExpr); if (typeIsByte) // for byte op. the remainder is stored in 'ah' instead { context.Generator.Write(0x8A, 0xD4); // mov dl, ah } return(new ExpressionResult(type, new PreferredRegister(Register64.RDX).MakeFor(type))); } throw new NotImplementedException( $"{nameof(BinaryOperationCompiler)}: {nameof(CompileModolu)}: I do not know how to compile this type: {type}" ); }
public ExpressionResult Compile( ArrayAllocationExpression expression, PreferredRegister target, ICompilationContext context ) { var codeGen = context.Generator; var linkingInfo = context.Linking; var index = context.CompileExpression(expression.Count, new PreferredRegister(Register64.R8)); var indexType = index.ValueType; var valueTypeSize = (sbyte)expression.Type.SizeOf(); Constants.LongType.AssertCanAssignImplicitly(indexType); // Array allocation compiles to function call of HeapAlloc (kernel32) index.GenerateMoveTo(Register64.R8, Constants.LongType, codeGen, linkingInfo); // Parameter 3: byte count if (valueTypeSize > 1) { codeGen.Shl(Register64.R8, (sbyte)Math.Log(valueTypeSize, 2)); // 8 byte type -> multiply count by 8 by shifting left 3 } codeGen.Add(Register64.R8, (sbyte)8); // llama length value codeGen.MovFromDereferenced4(Register64.RCX, Constants.DummyOffsetInt); linkingInfo.FixDataOffset(codeGen.StreamPosition, Constants.HeapHandleIdentifier); // Parameter 1: DefaultHeapHandle codeGen.Xor(Register64.RDX, Register64.RDX); codeGen.Add(Register64.RDX, (sbyte)(0x8 + 0x4)); // Parameter 2: HEAP_ZERO_MEMORY + HEAP_GENERATE_EXCEPTIONS codeGen.CallDereferenced4(Constants.DummyOffsetInt); linkingInfo.FixIATEntryOffset(codeGen.StreamPosition, "kernel32.dll", "HeapAlloc"); return(new ExpressionResult(new Type(expression.Type, Type.WrappingType.ArrayOf), Register64.RAX)); }
public ExpressionResult Compile( IExpression expression, PreferredRegister target, ICompilationContext context ) { switch (expression) { case ArrayAccessExpression arrayAccessExpression: return(context.CompileExpression(arrayAccessExpression, target)); case ArrayAllocationExpression arrayAllocationExpression: return(context.CompileExpression(arrayAllocationExpression, target)); case AtomicExpression atomicExpression: return(context.CompileExpression(atomicExpression, target)); case BinaryOperatorExpression binaryOperatorExpression: return(context.CompileExpression(binaryOperatorExpression, target)); case FunctionCallExpression methodCallExpression: return(context.CompileExpression(methodCallExpression, target)); case TypeCastExpression typeCastExpression: return(context.CompileExpression(typeCastExpression, target)); case UnaryOperatorExpression unaryOperatorExpression: return(context.CompileExpression(unaryOperatorExpression, target)); default: throw new NotImplementedException($"Compiler for expression type \"{expression.GetType().Name}\" has not yet been implemented"); } }
private static ExpressionResult CompileComparison( IExpression left, IExpression right, PreferredRegister target, ICompilationContext context, Action <sbyte> comparisonJmpSigned, Action <sbyte> comparisonJmpUnsignedd, bool inverted = false ) { var(leftReg, rightExpr, type) = PrepareBinaryExpression( left, right, target, context, true ); if (type.IsIntegerRegisterType()) { rightExpr.CmpTo(leftReg, context.Generator, context.Linking); } else if (type == Constants.DoubleType) { rightExpr.ComisdTo(leftReg, context.Generator, context.Linking); } else if (type == Constants.FloatType) { rightExpr.ComissTo(leftReg, context.Generator, context.Linking); } else { throw new NotImplementedException( $"{nameof(BinaryOperationCompiler)}: {nameof(CompileComparison)}: I do not know how to compile this type: {type}" ); } var targetRegister = target.MakeFor(Constants.BoolType); var mov1CodeGen = new CodeGen(); mov1CodeGen.Mov(targetRegister.AsR32(), inverted ? 0 : 1); var mov0CodeGen = new CodeGen(); mov0CodeGen.Mov(targetRegister.AsR32(), inverted ? 1 : 0); mov0CodeGen.Jmp(mov1CodeGen.GetBufferSpan().Length); if (type.IsSignedInteger()) { comparisonJmpSigned((sbyte)mov0CodeGen.GetBufferSpan().Length); } else { comparisonJmpUnsignedd((sbyte)mov0CodeGen.GetBufferSpan().Length); } context.Generator.Write(mov0CodeGen.GetBufferSpan()); context.Generator.Write(mov1CodeGen.GetBufferSpan()); return(new ExpressionResult(Constants.BoolType, targetRegister)); }
public ExpressionResult Compile(UnaryOperatorExpression expression, PreferredRegister target, ICompilationContext context) { return(expression.Operator.Operator.Kind switch { TokenKind.Minus => CompileMinus(expression, target, context), TokenKind.AddressOf => CompileAddressOf(expression, target, context), TokenKind.Not => CompileNot(expression, target, context), TokenKind.Pointer => CompileDereference(expression, target, context), _ => throw new NotImplementedException( $"{nameof(UnaryOperationCompiler)}: I do not know how to compile {expression.Operator.Operator}" ) });
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 ExpressionResult Compile( AtomicExpression expression, PreferredRegister target, ICompilationContext context ) { return(expression.Token.Kind switch { TokenKind.Identifier => CompileIdentifier(expression, context.Generator, context.Symbols), TokenKind.FloatLiteral => CompileFloatLiteral(expression), TokenKind.IntegerLiteral => CompileIntegerLiteral(expression), TokenKind.StringLiteral => CompileStringLiteral(expression, context.Generator, target, context.Linking), TokenKind.True => CompileTrue(context.Generator, target), TokenKind.False => CompileFalse(context.Generator, target), _ => throw new NotImplementedException($"Atomic expression type {expression.Token.Kind} not implemented") });
public void Compile( Return statement, ICompilationContext context ) { if (statement.ReturnValue != null) { var returnRegisters = new PreferredRegister(Register64.RAX, XmmRegister.XMM0); var returnResult = context.CompileExpression(statement.ReturnValue, returnRegisters); var myFunction = context.Symbols.GetFunctionDeclaration(context.Symbols.CurrentFunctionIdentifier); returnResult.GenerateMoveTo(returnRegisters.MakeFor(myFunction.ReturnType), myFunction.ReturnType, context.Generator, context.Linking); } context.Generator.Jmp(Constants.DummyOffsetInt); context.Linking.FixFunctionEpilogueOffset(context.Generator.StreamPosition, context.Symbols.CurrentFunctionIdentifier); }
/// <summary> /// Evaluates two expressions, and brings them to a common type. Tries to keep the second expression as reference, for /// mor optimal code generation. /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <param name="preferredFirst"></param> /// <param name="codeGen"></param> /// <param name="storageManager"></param> /// <param name="scope"></param> /// <param name="linkingInfo"></param> /// <param name="context"></param> /// <param name="shouldDereferenceForImplicitCast">The reference may be deferenced to cast it to the common type</param> /// <returns></returns> private static (Register register, ExpressionResult reference, Type type) PrepareBinaryExpression( IExpression first, IExpression second, PreferredRegister preferredFirst, ICompilationContext context, bool shouldDereferenceForImplicitCast = false ) { var firstResult = context.CompileExpression(first, preferredFirst); var isfirstIntegerType = firstResult.ValueType.IsIntegerRegisterType(); var firstTemp = context.Storage.Allocate(isfirstIntegerType); firstTemp.Store(firstResult, context.Generator, context.Linking); var secondResult = context.CompileExpression(second, preferredFirst); var type = firstResult.ValueType; if (firstResult.ValueType != secondResult.ValueType) { if (secondResult.ValueType.CanAssignImplicitly(firstResult.ValueType)) { type = secondResult.ValueType; } else if (shouldDereferenceForImplicitCast && firstResult.ValueType.CanAssignImplicitly(secondResult.ValueType)) { type = firstResult.ValueType; var secondDerefVolatile = secondResult.GetOccupiedOrVolatile(type); secondResult.GenerateMoveTo(secondDerefVolatile, type, context.Generator, context.Linking); secondResult = new ExpressionResult(type, secondDerefVolatile); } else { throw new TypeMismatchException("Any common type", $"{firstResult.ValueType} and {secondResult.ValueType}"); } } var preferredRegister = preferredFirst.MakeFor(type); var firstRegister = secondResult.IsOccopied(preferredRegister) ? secondResult.GetUnoccupiedVolatile(type) : preferredRegister; firstTemp.AsExpressionResult(firstResult.ValueType).GenerateMoveTo(firstRegister, type, context.Generator, context.Linking); context.Storage.Release(firstTemp); return(firstRegister, secondResult, type); }
private static ExpressionResult CompileMultiply( IExpression left, IExpression right, PreferredRegister target, ICompilationContext context ) { var tempRegister = new PreferredRegister(Register64.RAX, target.FloatRegister); var(leftReg, rightExpr, type) = PrepareBinaryExpression( left, right, tempRegister, context, true ); if (type.IsIntegerRegisterType()) { if (type.SizeOf() == 1) { throw new NotImplementedException("Multiplications with 8-bit types are not implemented"); } rightExpr.ImulTo(leftReg, context.Generator, context.Linking); } else if (type == Constants.DoubleType) { rightExpr.MulsdTo(leftReg, context.Generator, context.Linking); } else if (type == Constants.FloatType) { rightExpr.MulssTo(leftReg, context.Generator, context.Linking); } else { throw new NotImplementedException( $"{nameof(BinaryOperationCompiler)}: {nameof(CompileMultiply)}: I do not know how to compile this type: {type}" ); } return(new ExpressionResult(type, leftReg)); }
private static ExpressionResult CompileDivide( IExpression left, IExpression right, PreferredRegister target, ICompilationContext context ) { var leftRegisterPref = new PreferredRegister(Register64.RAX, target.FloatRegister); var(leftReg, rightExpr, type) = PrepareBinaryExpression( left, right, leftRegisterPref, context, true ); if (type.IsIntegerRegisterType()) { CompileIntegerDivision(context.Generator, context.Linking, type, leftReg, rightExpr); return(new ExpressionResult(type, new PreferredRegister(Register64.RAX).MakeFor(type))); } if (type == Constants.DoubleType) { rightExpr.DivsdTo(leftReg, context.Generator, context.Linking); } else if (type == Constants.FloatType) { rightExpr.DivssTo(leftReg, context.Generator, context.Linking); } else { throw new NotImplementedException( $"{nameof(BinaryOperationCompiler)}: {nameof(CompileDivide)}: I do not know how to compile this type: {type}" ); } return(new ExpressionResult(type, leftReg)); }
public ExpressionResult Compile( ArrayAccessExpression expression, PreferredRegister target, ICompilationContext context ) { var arrayTemp = context.Storage.Allocate(true); var array = context.CompileExpression(expression.Array, arrayTemp.IsRegister ? arrayTemp.Register : Register64.RAX); var arrayType = array.ValueType; arrayTemp.Store(array, context.Generator, context.Linking); const Register64 structOffsetRegister = Register64.RCX; const Register64 arrayRegister = Register64.RAX; var arrayIndex = context.CompileExpression(expression.Index, new PreferredRegister(structOffsetRegister)); Constants.LongType.AssertCanAssignImplicitly(arrayIndex.ValueType); arrayIndex.GenerateMoveTo(structOffsetRegister, Constants.LongType, context.Generator, context.Linking); arrayTemp.AsExpressionResult(arrayType).GenerateMoveTo(arrayRegister, context.Generator, context.Linking); context.Storage.Release(arrayTemp); if (arrayType == Constants.CstrType) { return(new ExpressionResult(Constants.SbyteType, arrayRegister, structOffsetRegister, 1)); } var itemType = arrayType.Child; if (arrayType.ChildRelation == Type.WrappingType.PointerOf) { return(new ExpressionResult(itemType, arrayRegister, structOffsetRegister, (byte)itemType.SizeOf())); } if (arrayType.ChildRelation == Type.WrappingType.ArrayOf) { return(new ExpressionResult(itemType, arrayRegister, structOffsetRegister, (byte)itemType.SizeOf(), 8)); } throw new TypeMismatchException("Array or pointer", arrayType.ToString()); }
private static ExpressionResult CompileAny( IExpression left, IExpression right, Action <ExpressionResult, Register, CodeGen, ILinkingInfo> actionInt, Action <ExpressionResult, Register, CodeGen, ILinkingInfo> actionFloat, Action <ExpressionResult, Register, CodeGen, ILinkingInfo> actionDouble, PreferredRegister target, ICompilationContext context ) { var(leftReg, rightExpr, type) = PrepareBinaryExpression( left, right, target, context, true ); if (type.IsIntegerRegisterType()) { actionInt(rightExpr, leftReg, context.Generator, context.Linking); } else if (type == Constants.DoubleType) { actionDouble(rightExpr, leftReg, context.Generator, context.Linking); } else if (type == Constants.FloatType) { actionFloat(rightExpr, leftReg, context.Generator, context.Linking); } else { throw new NotImplementedException( $"{nameof(BinaryOperationCompiler)}: {nameof(CompileAny)}: I do not know how to compile this type: {type}" ); } return(new ExpressionResult(type, leftReg)); }
private static ExpressionResult CompileAssign(IExpression left, IExpression right, PreferredRegister target, ICompilationContext context) { var(expression, assign, type) = PrepareBinaryExpression(right, left, target, context); assign.GenerateAssign(expression, context.Generator, context.Linking); return(assign); }
public ExpressionResult Compile( BinaryOperatorExpression expression, PreferredRegister target, ICompilationContext context ) { switch (expression.Operator.Operator.Kind) { case TokenKind.Plus: return(CompileAny( expression.Left, expression.Right, ExpressionResultExtensions.AddTo, ExpressionResultExtensions.AddsdTo, ExpressionResultExtensions.AddssTo, target, context )); case TokenKind.Minus: return(CompileAny( expression.Left, expression.Right, ExpressionResultExtensions.SubTo, ExpressionResultExtensions.SubsdTo, ExpressionResultExtensions.SubssTo, target, context )); case TokenKind.Pointer: return(CompileMultiply(expression.Left, expression.Right, target, context)); case TokenKind.Divide: return(CompileDivide(expression.Left, expression.Right, target, context)); case TokenKind.Modolu: return(CompileModolu(expression.Left, expression.Right, target, context)); case TokenKind.Assignment: return(CompileAssign(expression.Left, expression.Right, target, context)); case TokenKind.Equals: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Je, context.Generator.Je )); case TokenKind.NotEquals: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Jne, context.Generator.Jne )); case TokenKind.OpenAngularBracket: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Jl, context.Generator.Jb )); case TokenKind.CloseAngularBracket: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Jg, context.Generator.Ja )); case TokenKind.GreaterEquals: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Jge, context.Generator.Jae )); case TokenKind.SmallerEquals: return(CompileComparison( expression.Left, expression.Right, target, context, context.Generator.Jbe, context.Generator.Jle )); default: throw new NotImplementedException($"Compilation for Operator {expression.Operator.Operator.Kind} is not implemented"); } }
public ExpressionResult Compile( TypeCastExpression expression, PreferredRegister target, ICompilationContext context ) { var source = context.CompileExpression(expression.CastExpression, target); var sourceType = source.ValueType; var targetType = expression.Type; if (sourceType == targetType) { return(source); } if (CanCastUnsafe(targetType, sourceType)) { source.ChangeTypeUnsafe(targetType); return(source); } var targetRegister = target.MakeFor(targetType); if (targetType.ChildRelation == Type.WrappingType.PointerOf && // Allow array to pointer casts if the underlying type is identical sourceType.ChildRelation == Type.WrappingType.ArrayOf && sourceType.Child == targetType.Child) { source.GenerateMoveTo(targetRegister, context.Generator, context.Linking); context.Generator.Add(targetRegister.AsR64(), (sbyte)8); return(new ExpressionResult(targetType, targetRegister)); } // we're done with pointer and array casting. Only value casting down below if (targetType.ChildRelation != Type.WrappingType.None || sourceType.ChildRelation != Type.WrappingType.None) { ThrowBadCast(sourceType, targetType); } var sourceTypeSize = sourceType.SizeOf(); var targetTypeSize = targetType.SizeOf(); var sourceIsInt = sourceType.IsIntegerRegisterType(); var targetIsInt = targetType.IsIntegerRegisterType(); if (sourceType == Constants.CstrType || targetType == Constants.CstrType) { ThrowBadCast(sourceType, targetType); } if (sourceIsInt && targetIsInt) { if (targetTypeSize > sourceTypeSize) { // int register widening - works implicitly - isCast flag given to do signed <-> unsigned conversion by force source.GenerateMoveTo(targetRegister, targetType, context.Generator, context.Linking, true); return(new ExpressionResult(targetType, targetRegister)); } // int register narrowing source.GenerateMoveTo(targetRegister, context.Generator, context.Linking); // // clean rest of register //if (targetTypeSize == 4) // codeGen.Mov(targetRegister.AsR32(), targetRegister.AsR32()); //else // codeGen.And(targetRegister.AsR32(), targetTypeSize == 2 ? ushort.MaxValue : byte.MaxValue); return(new ExpressionResult(targetType, targetRegister)); } if (!sourceIsInt && !targetIsInt) // float <-> double conversions { source.GenerateMoveTo(targetRegister, context.Generator, context.Linking); if (targetTypeSize < sourceTypeSize) { context.Generator.CvtSd2Ss(targetRegister.AsFloat(), targetRegister.AsFloat()); } else { context.Generator.CvtSs2Sd(targetRegister.AsFloat(), targetRegister.AsFloat()); } return(new ExpressionResult(targetType, targetRegister)); } if (!sourceIsInt) /* && targetIsInt) */ { return(CastFloatToInt(sourceType, targetType, targetRegister, source, context.Generator, context.Linking)); } /* if (!targetIsInt && sourceIsInt) */ return(CastIntToFloat(sourceType, targetType, targetRegister, source, context.Generator, context.Linking)); }