Esempio n. 1
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));
        }
Esempio n. 2
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");
            }
        }
        /// <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);
        }
Esempio n. 4
0
        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());
        }
Esempio n. 5
0
        public void Compile(
            CodeBlock statement,
            ICompilationContext context
            )
        {
            context.Symbols.PushLocalScope();
            foreach (var subStatement in statement.Statements)
            {
                switch (subStatement)
                {
                case CodeBlock codeBlock:
                    Compile(codeBlock, context);
                    break;

                case Declaration declaration:
                    context.CompileStatement(declaration);
                    break;

                case For @for:
                    context.CompileStatement(@for);
                    break;

                case If @if:
                    context.CompileStatement(@if);
                    break;

                case While @while:
                    context.CompileStatement(@while);
                    break;

                case Return @return:
                    context.CompileStatement(@return);
                    break;

                case IExpression expression:
                    context.CompileExpression(
                        expression,
                        new PreferredRegister(Register64.RAX, XmmRegister.XMM0)
                        );
                    break;

                default:
                    throw new NotImplementedException(
                              $"{nameof(CodeBlockCompiler)}: I do not know how to compile: {subStatement.GetType().Name}"
                              );
                }
            }

            context.Symbols.PopLocalScope();
        }
Esempio n. 6
0
        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));
            }
        }
Esempio n. 7
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);
        }
Esempio n. 8
0
        public void Compile(Declaration statement, ICompilationContext context)
        {
            context.Symbols.DefineLocal(statement.Identifier.RawText, statement.Type);
            if (statement.InitialValue == null)
            {
                context.Generator.Xor(Register64.RAX, Register64.RAX);
                context.Generator.MovToDereferenced(Register64.RSP, Register64.RAX, context.Symbols.GetLocalOffset(statement.Identifier.RawText));
            }
            else
            {
                var initialValue         = context.CompileExpression(statement.InitialValue, PreferredRegister.DefaultVolatile);
                var initialValueRegister = initialValue.ToRegister(statement.Type, context.Generator, context.Linking);

                context.Symbols.GetLocalReference(statement.Identifier.RawText)
                .GenerateAssign(initialValueRegister, context.Generator, context.Linking);
            }
        }
Esempio n. 9
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);
        }
Esempio n. 10
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));
        }