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));
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #5
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));
        }