Esempio n. 1
0
 private static LLVMValueRef BuildLoadFieldPointer(
     LLVMBuilderRef Builder,
     LLVMValueRef Delegate,
     uint FieldIndex,
     string FieldName)
 {
     return(AtAddressEmitVariable.BuildConstantLoad(
                Builder,
                BuildStructGEP(
                    Builder,
                    Delegate,
                    FieldIndex,
                    FieldName + "_ptr"),
                FieldName));
 }
Esempio n. 2
0
 /// <summary>
 /// Creates a sequence of instructions that computes the type ID
 /// for the given VTable pointer.
 /// </summary>
 /// <param name="Builder">The builder to create the instructions in.</param>
 /// <param name="VTablePtr">A pointer to a VTable.</param>
 /// <returns>A type ID.</returns>
 public static LLVMValueRef BuildTypeid(
     LLVMBuilderRef Builder,
     LLVMValueRef VTablePtr)
 {
     return(AtAddressEmitVariable.BuildConstantLoad(
                Builder,
                BuildStructGEP(
                    Builder,
                    BuildBitCast(
                        Builder,
                        VTablePtr,
                        PointerType(LLVMType.VTableType, 0),
                        "vtable_tmp"),
                    0,
                    "typeid_ptr_tmp"),
                "typeid_tmp"));
 }
Esempio n. 3
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));
        }
Esempio n. 4
0
        /// <summary>
        /// Generates code that computes the address of the given callee function's
        /// implementation.
        /// </summary>
        /// <param name="BasicBlock">The basic block to generate code in.</param>
        /// <param name="Target">The object that receives the call.</param>
        /// <param name="Callee">The callee method.</param>
        /// <param name="Op">The call operator.</param>
        /// <returns>A function pointer.</returns>
        public static BlockCodegen EmitCallee(
            BasicBlockBuilder BasicBlock,
            LLVMValueRef Target,
            IMethod Callee,
            Operator Op)
        {
            var module = BasicBlock.FunctionBody.Module;

            if (Op.Equals(Operator.GetDelegate) ||
                Op.Equals(Operator.GetCurriedDelegate))
            {
                return(new BlockCodegen(BasicBlock, module.Declare(Callee)));
            }
            else if (Op.Equals(Operator.GetVirtualDelegate))
            {
                var method = (LLVMMethod)Callee;

                if (method.DeclaringType.GetIsValueType() ||
                    !method.GetIsVirtual() ||
                    Target.Pointer == IntPtr.Zero)
                {
                    return(EmitCallee(BasicBlock, Target, Callee, Operator.GetDelegate));
                }

                var vtablePtr = BuildBitCast(
                    BasicBlock.Builder,
                    Target,
                    PointerType(PointerType(LLVMType.VTableType, 0), 0),
                    "vtable_ptr_tmp");

                var vtable = AtAddressEmitVariable.BuildConstantLoad(
                    BasicBlock.Builder,
                    vtablePtr,
                    "vtable_tmp");

                if (method.DeclaringType.GetIsInterface())
                {
                    // Resolve interface method implementations by calling a stub.
                    var typeIndexPtr = BuildStructGEP(
                        BasicBlock.Builder,
                        vtable,
                        1,
                        "type_index_ptr");

                    var typeIndex = AtAddressEmitVariable.BuildConstantLoad(
                        BasicBlock.Builder,
                        typeIndexPtr,
                        "type_ptr");

                    var stub = module.GetInterfaceStub(method);

                    var methodImpl = BuildCall(
                        BasicBlock.Builder,
                        stub.Function,
                        new LLVMValueRef[] { typeIndex },
                        "iface_method_ptr");

                    return(new BlockCodegen(BasicBlock, methodImpl));
                }
                else
                {
                    // Resolve virtual/abstract method implementations by performing
                    // a table lookup.
                    var vtableSlot = module
                                     .GetVTable(method.ParentType)
                                     .GetAbsoluteSlot(method);

                    var vtableContentPtr = BuildBitCast(
                        BasicBlock.Builder,
                        BuildStructGEP(
                            BasicBlock.Builder,
                            vtable,
                            2,
                            "vtable_method_array_ptr"),
                        PointerType(PointerType(Int8Type(), 0), 0),
                        "vtable_methods_ptr");

                    var vtableSlotPtr = BuildGEP(
                        BasicBlock.Builder,
                        vtableContentPtr,
                        new LLVMValueRef[] { ConstInt(Int32Type(), (ulong)vtableSlot, false) },
                        "vtable_slot_ptr");

                    var methodImpl = AtAddressEmitVariable.BuildConstantLoad(
                        BasicBlock.Builder,
                        BuildBitCast(
                            BasicBlock.Builder,
                            vtableSlotPtr,
                            PointerType(PointerType(module.DeclarePrototype(method), 0), 0),
                            "method_ptr_field"
                            ),
                        "method_ptr");

                    return(new BlockCodegen(BasicBlock, methodImpl));
                }
            }
            else
            {
                throw new NotImplementedException(
                          string.Format("Unsupported call operator: {0}.", Op.Name));
            }
        }
Esempio n. 5
0
 public CatchHeader(IType ExceptionType, AtAddressEmitVariable ExceptionVariable)
 {
     this.ExceptionType = ExceptionType;
     this.exceptionVar  = ExceptionVariable;
 }
Esempio n. 6
0
        /// <summary>
        /// Populates the given 'catch' block.
        /// </summary>
        /// <param name="CatchBlock">The 'catch' block to populate.</param>
        /// <param name="LeaveBlock">The 'leave' block to jump to when the 'catch' is done.</param>
        private void PopulateCatchBlock(BasicBlockBuilder CatchBlock, BasicBlockBuilder LeaveBlock)
        {
            var catchBlockEntry = CatchBlock;

            // Before we even get started on the catch block's body, we should first
            // take the time to ensure that the '__cxa_begin_catch' environment set up
            // by the catch block is properly terminated by a '__cxa_end_catch' call,
            // even if an exception is thrown from the catch block itself. We can do
            // so by creating a 'catch_end' block and a thunk landing pad.
            var catchEndBlock       = CatchBlock.CreateChildBlock("catch_end");
            var catchExceptionBlock = CatchBlock.CreateChildBlock("catch_exception");

            var catchEndLandingPadBlock = CatchBlock.CreateChildBlock("catch_end_landingpad");

            ItaniumCxxFinallyBlock.PopulateThunkLandingPadBlock(
                catchEndLandingPadBlock,
                catchExceptionBlock.Block,
                true);

            CatchBlock = CatchBlock.WithUnwindTarget(catchEndLandingPadBlock, catchEndBlock);

            // The catch block starts like this:
            //
            // catch:
            //     %exception_data = load { i8*, i32 }* %exception_data_alloca
            //     %exception_obj = extractvalue { i8*, i32 } %exception_data, 0
            //     %exception_ptr_opaque = call i8* @__cxa_begin_catch(i8* %exception_obj)
            //     %exception_ptr = bitcast i8* %exception_ptr_opaque to i8**
            //     %exception = load i8*, i8** %exception_ptr
            //     %exception_vtable_ptr_ptr = bitcast i8* %exception to i8**
            //     %exception_vtable_ptr = load i8*, i8** %exception_vtable_ptr_ptr
            //     %exception_typeid = <typeid> i64, i8* %exception_vtable_ptr

            var exceptionData = BuildLoad(
                CatchBlock.Builder,
                CatchBlock.FunctionBody.ExceptionDataStorage.Value,
                "exception_data");

            var exceptionObj = BuildExtractValue(
                CatchBlock.Builder,
                exceptionData,
                0,
                "exception_obj");

            var exceptionPtrOpaque = BuildCall(
                CatchBlock.Builder,
                CatchBlock.FunctionBody.Module.Declare(IntrinsicValue.CxaBeginCatch),
                new LLVMValueRef[] { exceptionObj },
                "exception_ptr_opaque");

            var exceptionPtr = BuildBitCast(
                CatchBlock.Builder,
                exceptionPtrOpaque,
                PointerType(PointerType(Int8Type(), 0), 0),
                "exception_ptr");

            var exception = BuildLoad(CatchBlock.Builder, exceptionPtr, "exception");

            var exceptionVtablePtrPtr = BuildBitCast(
                CatchBlock.Builder,
                exception,
                PointerType(PointerType(Int8Type(), 0), 0),
                "exception_vtable_ptr_ptr");

            var exceptionVtablePtr = AtAddressEmitVariable.BuildConstantLoad(
                CatchBlock.Builder,
                exceptionVtablePtrPtr,
                "exception_vtable_ptr");

            var exceptionTypeid = TypeIdBlock.BuildTypeid(
                CatchBlock.Builder,
                exceptionVtablePtr);

            // Next, we need to figure out if we have a catch block that can handle the
            // exception we've thrown. We do so by iterating over all catch blocks and
            // testing if they're a match for the exception's type.
            var fallthroughBlock = CatchBlock.CreateChildBlock("catch_test");

            for (int i = 0; i < CatchClauses.Count; i++)
            {
                var clause = CatchClauses[i];

                var catchBodyBlock     = CatchBlock.CreateChildBlock("catch_body");
                var catchBodyBlockTail = catchBodyBlock;

                // First, emit the catch body. This is just a regular block that
                // clears the exception value variable when it gets started and
                // jumps to the 'catch_end' when it's done.
                //
                // catch_body:
                //     %exception_val = bitcast i8* %exception to <clause_type>
                //     store <clause_type> %exception_val, <clause_type>* %clause_exception_variable_alloca
                //     <catch clause body>
                //     br catch_end

                var ehVarAddressAndBlock = clause.LLVMHeader
                                           .AtAddressExceptionVariable.Address.Emit(catchBodyBlockTail);
                catchBodyBlockTail = ehVarAddressAndBlock.BasicBlock;

                BuildStore(
                    catchBodyBlockTail.Builder,
                    BuildBitCast(
                        catchBodyBlockTail.Builder,
                        exception,
                        catchBodyBlockTail.FunctionBody.Module.Declare(clause.ExceptionType),
                        "exception_val"),
                    ehVarAddressAndBlock.Value);

                catchBodyBlockTail = clause.Body.Emit(catchBodyBlockTail).BasicBlock;

                BuildBr(catchBodyBlockTail.Builder, catchEndBlock.Block);

                // Each clause is implemented as:
                //
                // catch_clause:
                //     %clause_typeid = <typeid> i64, clause-exception-type
                //     %typeid_rem = urem i64 %exception_typeid_tmp, %clause_typeid
                //     %is_subtype = cmp eq i64 %typeid_rem, 0
                //     br i1 %is_subtype, label %catch_body, label %fallthrough
                //
                var clauseTypeid = CatchBlock.FunctionBody.Module.GetTypeId((LLVMType)clause.ExceptionType);

                var typeIdRem = BuildURem(
                    CatchBlock.Builder,
                    exceptionTypeid,
                    ConstInt(exceptionTypeid.TypeOf(), clauseTypeid, false),
                    "typeid_rem");

                var isSubtype = BuildICmp(
                    CatchBlock.Builder,
                    LLVMIntPredicate.LLVMIntEQ,
                    typeIdRem,
                    ConstInt(exceptionTypeid.TypeOf(), 0, false),
                    "is_subtype");

                BuildCondBr(CatchBlock.Builder, isSubtype, catchBodyBlock.Block, fallthroughBlock.Block);

                CatchBlock       = fallthroughBlock;
                fallthroughBlock = CatchBlock.CreateChildBlock("catch_test");
            }

            // If we didn't match any catch clauses, then we'll rethrow the exception and
            // unwind to the end-catch landing pad.
            //
            // no_matching_clause:
            //     invoke void @__cxa_rethrow() to label %unreachable unwind label %catch_end_landingpad
            //
            // unreachable:
            //     unreachable
            BuildInvoke(
                CatchBlock.Builder,
                CatchBlock.FunctionBody.Module.Declare(IntrinsicValue.CxaRethrow),
                new LLVMValueRef[] { },
                fallthroughBlock.Block,
                catchEndLandingPadBlock.Block,
                "");
            BuildUnreachable(fallthroughBlock.Builder);

            // The catch end block simply calls '__cxa_end_catch' and jumps to the 'leave'
            // block. Like so:
            //
            // catch_end:
            //     call void @__cxa_end_catch()
            //     br label %leave

            BuildCall(
                catchEndBlock.Builder,
                CatchBlock.FunctionBody.Module.Declare(IntrinsicValue.CxaEndCatch),
                new LLVMValueRef[] { },
                "");
            BuildBr(catchEndBlock.Builder, LeaveBlock.Block);

            // The 'catch exception' block is entered when an exception is thrown from
            // the 'catch' block, or if the catch block is ill-equipped to handle the
            // exception. Its responsibility is to end the catch block and jump to
            // the manual unwind target.
            //
            // catch_exception:
            //     call void @__cxa_end_catch()
            //     br label %manual_unwind_target

            BuildCall(
                catchExceptionBlock.Builder,
                catchExceptionBlock.FunctionBody.Module.Declare(IntrinsicValue.CxaEndCatch),
                new LLVMValueRef[] { },
                "");
            BuildBr(catchExceptionBlock.Builder, ItaniumCxxFinallyBlock.GetManualUnwindTarget(catchBlockEntry));
        }