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}"
                      );
        }
Exemple #2
0
        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));
        }
Exemple #3
0
        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));
        }
Exemple #5
0
 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}"
             )
     });
Exemple #6
0
        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")
     });
Exemple #8
0
        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");
            }
        }
Exemple #16
0
        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));
        }