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 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( 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); }
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)); }