Пример #1
0
        public ICodeBlock EmitUnary(ICodeBlock Value, Operator Op)
        {
            var valBlock = (CodeBlock)Value;
            var valType  = valBlock.Type;

            if (Op.Equals(Operator.Not))
            {
                return(new UnaryBlock(this, valBlock, valType, BuildNot, ConstNot));
            }
            else if (Op.Equals(Operator.Subtract))
            {
                if (valType.GetIsFloatingPoint())
                {
                    return(new UnaryBlock(this, valBlock, valType, BuildFNeg, ConstFNeg));
                }
                else
                {
                    return(new UnaryBlock(this, valBlock, valType, BuildNeg, ConstNeg));
                }
            }
            else if (Op.Equals(Operator.Box))
            {
                // To box a value x, we create a struct `{ typeof(x).vtable, x }`
                // and store it in the heap.
                // So we basically want to do this:
                //
                //     var ptr = gcalloc(sizeof({ byte*, typeof(x) }));
                //     ptr->vtable = (byte*)T.vtable;
                //     ptr->value = x;
                //     ptr
                //
                var constructedType = valType.MakePointerType(PointerKind.BoxPointer);
                var tmp             = new SSAVariable("box_tmp", constructedType);
                var expr            = new InitializedExpression(
                    new BlockStatement(new IStatement[]
                {
                    tmp.CreateSetStatement(
                        Allocate(
                            ToExpression(new SizeOfBlock(this, constructedType, false)),
                            constructedType)),
                    new StoreAtAddressStatement(
                        GetVTablePtrExpr(tmp.CreateGetExpression()),
                        ToExpression(new TypeVTableBlock(this, (LLVMType)valType))),
                    new StoreAtAddressStatement(
                        CreateUnboxExpr(tmp.CreateGetExpression(), valType),
                        ToExpression(valBlock))
                }),
                    tmp.CreateGetExpression());
                return(expr.Emit(this));
            }
            else
            {
                throw new NotImplementedException(
                          string.Format(
                              "Unsupported unary op: {0} {1}",
                              Op.Name,
                              valType.FullName));
            }
        }
        /// <inheritdoc/>
        protected override IExpression Transform(IExpression Expression)
        {
            if (Expression is NewObjectExpression)
            {
                var expr            = (NewObjectExpression)Expression;
                var visitedExpr     = expr.Accept(this);
                var constructedType = expr.Type;
                if (!constructedType.GetIsReferenceType())
                {
                    return(visitedExpr);
                }

                // TODO: a type's finalizer is looked up every time an object is constructed.
                // That's a pretty expensive operation and we could speed it up greatly
                // by introducing a cache.
                var rootAncestor  = GetRootAncestor(constructedType);
                var rootFinalizer = GetFinalizer(rootAncestor);

                if (rootFinalizer == null)
                {
                    return(visitedExpr);
                }

                var finalizer = rootFinalizer.GetImplementation(constructedType) ?? rootFinalizer;

                if (finalizer.HasAttribute(
                        PrimitiveAttributes.Instance.NopAttribute.AttributeType))
                {
                    return(visitedExpr);
                }

                var tmp = new SSAVariable(constructedType);

                return(new InitializedExpression(
                           new BlockStatement(
                               new IStatement[]
                {
                    tmp.CreateSetStatement(visitedExpr),
                    GarbageCollector.RegisterFinalizer(
                        new ReinterpretCastExpression(
                            tmp.CreateGetExpression(),
                            PrimitiveTypes.Void.MakePointerType(PointerKind.TransientPointer)),
                        finalizer)
                }),
                           tmp.CreateGetExpression()));
            }
            else
            {
                return(Expression.Accept(this));
            }
        }
Пример #3
0
        public ICodeBlock EmitNewObject(IMethod Constructor, IEnumerable <ICodeBlock> Arguments)
        {
            var constructedType = Constructor.DeclaringType;

            if (constructedType.GetIsValueType())
            {
                throw new InvalidOperationException(
                          "cannot create a new 'struct' object; " +
                          "'struct' object creation must be lowered to " +
                          "method invocation before codegen");
            }
            else if (constructedType.GetIsReferenceType())
            {
                var tmp = new SSAVariable("class_tmp", constructedType);
                // Write the following code:
                //
                //     var ptr = gcalloc(sizeof(T));
                //     ptr->vtable = (byte*)T.vtable;
                //     ptr->ctor(args...);
                //     static if (!#builtin_has_attribute(T.Finalize, NopAttribute))
                //         register_finalizer(ptr, T.Finalize);
                //     ptr
                //

                var statements = new List <IStatement>();
                statements.Add(
                    tmp.CreateSetStatement(
                        Allocate(
                            ToExpression(new SizeOfBlock(this, constructedType, false)),
                            constructedType)));
                statements.Add(
                    new StoreAtAddressStatement(
                        GetVTablePtrExpr(tmp.CreateGetExpression()),
                        ToExpression(new TypeVTableBlock(this, (LLVMType)constructedType))));
                statements.Add(
                    new ExpressionStatement(
                        new InvocationExpression(
                            Constructor,
                            tmp.CreateGetExpression(),
                            Arguments.Cast <CodeBlock>()
                            .Select <CodeBlock, IExpression>(ToExpression)
                            .ToArray <IExpression>())));

                var expr = new InitializedExpression(
                    new BlockStatement(statements),
                    tmp.CreateGetExpression());
                return(expr.Emit(this));
            }
            throw new NotImplementedException();
        }
Пример #4
0
        public ICodeBlock EmitNewArray(IType ElementType, IEnumerable <ICodeBlock> Dimensions)
        {
            var arrayType = ElementType.MakeArrayType(Enumerable.Count <ICodeBlock>(Dimensions));

            // First, store all dimensions in temporaries.
            var statements = new List <IStatement>();
            var dimVals    = SpillDimensions(Dimensions, statements);
            var arrayTmp   = new SSAVariable("array_tmp", arrayType);

            // The number of elements to allocate is equal to the product of
            // the dimensions.
            var elemCount = EmitProduct(dimVals);

            // The size of the chunk of memory to allocate is
            //
            //     sizeof({ i32, ..., [0 x <element type>]}) + elemCount * sizeof(<element type>)
            //
            var allocationSize = EmitBinary(
                new SizeOfBlock(this, arrayType, false),
                EmitBinary(
                    elemCount,
                    new SizeOfBlock(this, ElementType, true),
                    Operator.Multiply),
                Operator.Add);

            // Allocate the array and store it in a temporary.
            statements.Add(
                arrayTmp.CreateSetStatement(
                    Allocate(
                        new CodeBlockExpression(allocationSize, PrimitiveTypes.Int32),
                        arrayType)));

            // Store the array's dimensions in the array header.
            StoreDimensionsInArrayHeader(
                (CodeBlock)arrayTmp.CreateGetExpression().Emit(this),
                dimVals,
                statements);

            return(EmitSequence(
                       new BlockStatement(statements).Emit(this),
                       arrayTmp.CreateGetExpression().Emit(this)));
        }
Пример #5
0
        public IUnmanagedEmitVariable GetUnmanagedElement(ICodeBlock Value, IEnumerable <ICodeBlock> Index)
        {
            var valBlock = (CodeBlock)Value;
            var valType  = valBlock.Type;

            if (valType.GetIsArray())
            {
                // Suppose that an n-dimensional array with dimensions
                //
                //     dim_1, dim_2, ..., dim_n
                //
                // is indexed with
                //
                //     i_1, i_2, ..., i_n.
                //
                // To compute a pointer to the element with that index, we can
                // use the following formula:
                //
                //     offset = i_1 + i_2 * dim_1 + i_3 * dim_1 * dim_2 + ... +
                //              i_n * dim_1 * dim_2 * ... * dim_n-1
                //
                //            = i_1 + dim_1 * (i_2 + dim_2 * (...))
                //
                // The latter identity requires fewer multiplications, so we'll use that.

                var arrayPtrTmp = new SSAVariable("array_tmp", valBlock.Type);
                var arrayPtr    = (CodeBlock)arrayPtrTmp.CreateGetExpression().Emit(this);
                var indexArray  = Index.ToArray <ICodeBlock>();
                var offset      = EmitInteger(new IntegerValue(0));
                for (int i = indexArray.Length - 1; i >= 0; i--)
                {
                    // offset <- i_i + dim_i * offset
                    offset = EmitBinary(
                        EmitTypeBinary(indexArray[i], PrimitiveTypes.Int32, Operator.StaticCast),
                        EmitBinary(
                            EmitDereferencePointer(new GetDimensionPtrBlock(this, arrayPtr, i)),
                            offset,
                            Operator.Multiply),
                        Operator.Add);
                }

                // Now add this offset to the data pointer of the array and dereference the result.
                return(new AtAddressEmitVariable(
                           (CodeBlock)EmitSequence(
                               arrayPtrTmp.CreateSetStatement(ToExpression(valBlock)).Emit(this),
                               EmitBinary(new GetDataPtrBlock(this, arrayPtr), offset, Operator.Add))));
            }

            throw new NotImplementedException();
        }
Пример #6
0
        private IReadOnlyList <ICodeBlock> SpillDimensions(
            IEnumerable <ICodeBlock> Dimensions,
            List <IStatement> Statements)
        {
            var dimVals = new List <ICodeBlock>();

            foreach (var dim in Dimensions)
            {
                var dimTmp = new SSAVariable("dimension_tmp", PrimitiveTypes.Int32);
                Statements.Add(
                    dimTmp.CreateSetStatement(
                        ToExpression(
                            (CodeBlock)EmitTypeBinary(dim, PrimitiveTypes.Int32, Operator.StaticCast))));
                dimVals.Add(dimTmp.CreateGetExpression().Emit(this));
            }
            return(dimVals);
        }