Beispiel #1
0
        public override BlockCodegen Emit(BasicBlockBuilder BasicBlock)
        {
            var delegateAndBlock = Delegate.Emit(BasicBlock);

            BasicBlock = delegateAndBlock.BasicBlock;

            var methodTypeAllocBlock = (CodeBlock)codeGen.Allocate(
                new StaticCastExpression(
                    LLVMCodeGenerator.ToExpression(
                        new ConstantBlock(codeGen, PrimitiveTypes.UInt64, SizeOf(DelegateBlock.MethodTypeLayout))),
                    PrimitiveTypes.UInt64),
                Type).Emit(codeGen);

            var methodTypeAllocCodegen = methodTypeAllocBlock.Emit(BasicBlock);

            BasicBlock = methodTypeAllocCodegen.BasicBlock;

            BuildStore(
                BasicBlock.Builder,
                AtAddressEmitVariable.BuildConstantLoad(
                    BasicBlock.Builder,
                    BuildBitCast(
                        BasicBlock.Builder,
                        delegateAndBlock.Value,
                        PointerType(DelegateBlock.MethodTypeLayout, 0),
                        "delegate_ptr"),
                    "delegate_data"),
                methodTypeAllocCodegen.Value);

            BuildStore(
                BasicBlock.Builder,
                TypeVTableBlock.BuildTypeVTable(BasicBlock, Type),
                BuildStructGEP(BasicBlock.Builder, methodTypeAllocCodegen.Value, 0, "vtable_ptr_ptr"));

            return(new BlockCodegen(BasicBlock, methodTypeAllocCodegen.Value));
        }
Beispiel #2
0
        public override BlockCodegen Emit(BasicBlockBuilder BasicBlock)
        {
            var targetAndBlock = InvocationBlock.EmitTarget(BasicBlock, Target);

            BasicBlock = targetAndBlock.BasicBlock;

            var calleeAndBlock = InvocationBlock.EmitCallee(BasicBlock, targetAndBlock.Value, Callee, Op);

            BasicBlock = calleeAndBlock.BasicBlock;

            var methodTypeAllocBlock = (CodeBlock)codeGen.Allocate(
                new StaticCastExpression(
                    LLVMCodeGenerator.ToExpression(
                        new ConstantBlock(codeGen, PrimitiveTypes.UInt64, SizeOf(MethodTypeLayout))),
                    PrimitiveTypes.UInt64),
                Type).Emit(codeGen);

            var methodTypeAllocCodegen = methodTypeAllocBlock.Emit(BasicBlock);

            BasicBlock = methodTypeAllocCodegen.BasicBlock;

            BuildStore(
                BasicBlock.Builder,
                TypeVTableBlock.BuildTypeVTable(BasicBlock, Type),
                BuildStructGEP(BasicBlock.Builder, methodTypeAllocCodegen.Value, 0, "vtable_ptr_ptr"));

            bool hasContext = targetAndBlock.Value.Pointer != IntPtr.Zero;

            if (hasContext)
            {
                BuildStore(
                    BasicBlock.Builder,
                    BuildBitCast(
                        BasicBlock.Builder,
                        targetAndBlock.Value,
                        PointerType(Int8Type(), 0),
                        "context_obj"),
                    BuildStructGEP(
                        BasicBlock.Builder,
                        methodTypeAllocCodegen.Value,
                        1,
                        "context_obj_ptr"));
            }

            BuildStore(
                BasicBlock.Builder,
                BuildBitCast(
                    BasicBlock.Builder,
                    calleeAndBlock.Value,
                    PointerType(Int8Type(), 0),
                    "opaque_func_ptr"),
                BuildStructGEP(
                    BasicBlock.Builder,
                    methodTypeAllocCodegen.Value,
                    2,
                    "func_ptr_ptr"));

            BuildStore(
                BasicBlock.Builder,
                ConstInt(Int1Type(), hasContext ? 1ul : 0ul, false),
                BuildStructGEP(BasicBlock.Builder, methodTypeAllocCodegen.Value, 3, "has_context_ptr"));

            return(new BlockCodegen(BasicBlock, methodTypeAllocCodegen.Value));
        }
Beispiel #3
0
        public ICodeBlock EmitTypeBinary(ICodeBlock Value, IType Type, Operator Op)
        {
            var valBlock = (CodeBlock)Value;

            if (Op.Equals(Operator.ReinterpretCast))
            {
                if (valBlock.Type.GetIsValueType() && Type.GetIsValueType())
                {
                    return(new RetypedBlock(this, valBlock, Type));
                }
                else
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildPointerCast, ConstPointerCast));
                }
            }
            else if (Op.Equals(Operator.IsInstance))
            {
                // If T is virtual/abstract/interface, then rewrite `x is T` as
                // `x != (decltype(x))null && x->vtable.typeid % T.vtable.typeid == 0`.
                //
                // Otherwise, we can use
                // `x != (decltype(x))null && x->vtable == T.vtable`.
                bool isVirtual = Type.GetIsVirtual() ||
                                 Type.GetIsAbstract() ||
                                 Type.GetIsInterface();

                var valTmp = DeclareLocal(new UniqueTag("is_tmp"), new TypeVariableMember(valBlock.Type));

                var valVTablePtr  = (CodeBlock)EmitDereferencePointer(EmitVTablePtr(valTmp.EmitGet()), true);
                var typeVTablePtr = new TypeVTableBlock(this, (LLVMType)Type);

                return(EmitSequence(
                           valTmp.EmitSet(valBlock),
                           this.EmitLogicalAnd(
                               EmitBinary(
                                   valTmp.EmitGet(),
                                   EmitTypeBinary(EmitNull(), valBlock.Type, Operator.ReinterpretCast),
                                   Operator.CheckInequality),
                               isVirtual
                            ? EmitBinary(
                                   EmitBinary(
                                       new TypeIdBlock(this, valVTablePtr),
                                       new TypeIdBlock(this, typeVTablePtr),
                                       Operator.Remainder),
                                   EmitInteger(new IntegerValue(0UL)),
                                   Operator.CheckEquality)
                            : EmitBinary(
                                   valVTablePtr,
                                   typeVTablePtr,
                                   Operator.CheckEquality))));
            }
            else if (Op.Equals(Operator.AsInstance))
            {
                // Rewrite `x as T` as `x is T ? x : null`.
                var valTmp = DeclareLocal(new UniqueTag("as_tmp"), new TypeVariableMember(valBlock.Type));
                return(EmitSequence(
                           valTmp.EmitSet(valBlock),
                           EmitIfElse(
                               EmitTypeBinary(valTmp.EmitGet(), Type, Operator.IsInstance),
                               EmitTypeBinary(valTmp.EmitGet(), Type, Operator.ReinterpretCast),
                               EmitTypeBinary(EmitNull(), Type, Operator.ReinterpretCast))));
            }
            else if (Op.Equals(Operator.DynamicCast))
            {
                // Rewrite `(T)x` as `x is T ? x : invalid-cast(T)`.
                var valTmp = DeclareLocal(new UniqueTag("dyn_cast_tmp"), new TypeVariableMember(valBlock.Type));
                return(EmitSequence(
                           valTmp.EmitSet(valBlock),
                           EmitIfElse(
                               EmitTypeBinary(valTmp.EmitGet(), Type, Operator.IsInstance),
                               EmitTypeBinary(valTmp.EmitGet(), Type, Operator.ReinterpretCast),
                               EmitThrowInvalidCast((CodeBlock)valTmp.EmitGet(), Type, Type))));
            }
            else if (Op.Equals(Operator.UnboxReference))
            {
                // Rewrite `#unbox_ref(x, T*)` as `x is T ? &x->value : invalid-cast(T)`.
                var elemType = Type.AsPointerType().ElementType;
                var valTmp   = DeclareLocal(new UniqueTag("unbox_ref_tmp"), new TypeVariableMember(valBlock.Type));
                return(EmitSequence(
                           valTmp.EmitSet(valBlock),
                           EmitIfElse(
                               EmitTypeBinary(valTmp.EmitGet(), elemType, Operator.IsInstance),
                               new UnboxBlock(this, (CodeBlock)valTmp.EmitGet(), elemType),
                               EmitThrowInvalidCast((CodeBlock)valTmp.EmitGet(), elemType, Type))));
            }
            else if (Op.Equals(Operator.UnboxValue))
            {
                if (Type.GetIsValueType())
                {
                    // If `T` is a `struct`, then `#unbox_val(x, T)` is equivalent to
                    // `*#unbox_ref(x, T*)`.
                    return(EmitDereferencePointer(
                               EmitTypeBinary(
                                   valBlock,
                                   Type.MakePointerType(PointerKind.TransientPointer),
                                   Operator.UnboxReference)));
                }
                else
                {
                    // If `T` is a `class`, then `#unbox_val(x, T)` is equivalent to
                    // `#dynamic_cast(x, T)`.
                    return(EmitTypeBinary(valBlock, Type, Operator.DynamicCast));
                }
            }
            else if (Op.Equals(Operator.StaticCast))
            {
                var valType = valBlock.Type;
                if (valType.GetIsInteger() && Type.GetIsInteger())
                {
                    var valSpec    = valType.GetIntegerSpec();
                    var targetSpec = Type.GetIntegerSpec();
                    if (valSpec.Size == targetSpec.Size)
                    {
                        return(new RetypedBlock(this, valBlock, Type));
                    }
                    else if (valSpec.Size > targetSpec.Size)
                    {
                        return(new SimpleCastBlock(this, valBlock, Type, BuildTrunc, ConstTrunc));
                    }
                    else if (valSpec.IsSigned)
                    {
                        return(new SimpleCastBlock(this, valBlock, Type, BuildSExt, ConstSExt));
                    }
                    else
                    {
                        return(new SimpleCastBlock(this, valBlock, Type, BuildZExt, ConstZExt));
                    }
                }
                else if (valType == PrimitiveTypes.Char)
                {
                    return(EmitTypeBinary(new RetypedBlock(this, valBlock, PrimitiveTypes.UInt16), Type, Op));
                }
                else if (Type == PrimitiveTypes.Char)
                {
                    return(new RetypedBlock(this, (CodeBlock)EmitTypeBinary(valBlock, PrimitiveTypes.UInt16, Op), Type));
                }
                else if (valType.GetIsPointer() && Type.GetIsInteger())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildPtrToInt, ConstPtrToInt));
                }
                else if (valType.GetIsInteger() && Type.GetIsPointer())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildIntToPtr, ConstIntToPtr));
                }
                else if (valType.GetIsSignedInteger() && Type.GetIsFloatingPoint())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildSIToFP, ConstSIToFP));
                }
                else if (valType.GetIsUnsignedInteger() && Type.GetIsFloatingPoint())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildUIToFP, ConstUIToFP));
                }
                else if (valType.GetIsFloatingPoint() && Type.GetIsSignedInteger())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildFPToSI, ConstFPToSI));
                }
                else if (valType.GetIsFloatingPoint() && Type.GetIsUnsignedInteger())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildFPToUI, ConstFPToUI));
                }
                else if (valType.GetIsFloatingPoint() && Type.GetIsFloatingPoint())
                {
                    return(new SimpleCastBlock(this, valBlock, Type, BuildFPCast, ConstFPCast));
                }
                else if (valType.GetIsEnum())
                {
                    return(EmitTypeBinary(new RetypedBlock(this, valBlock, valType.GetParent()), Type, Op));
                }
                else if (Type.GetIsEnum())
                {
                    return(new RetypedBlock(this, (CodeBlock)EmitTypeBinary(valBlock, Type.GetParent(), Op), Type));
                }
                else if (IsRuntimeDelegate(valType) && IsRuntimeDelegate(Type))
                {
                    if (object.Equals(Type, valType))
                    {
                        return(valBlock);
                    }
                    else if (valBlock is DelegateBlock)
                    {
                        var delegBlock = (DelegateBlock)valBlock;
                        return(new DelegateBlock(
                                   this,
                                   delegBlock.Callee,
                                   delegBlock.Target,
                                   delegBlock.Op,
                                   Type));
                    }
                    else
                    {
                        return(new DelegateCastBlock(this, valBlock, Type));
                    }
                }
            }
            throw new NotImplementedException();
        }