private static LLVMValueRef BuildLoadFieldPointer( LLVMBuilderRef Builder, LLVMValueRef Delegate, uint FieldIndex, string FieldName) { return(AtAddressEmitVariable.BuildConstantLoad( Builder, BuildStructGEP( Builder, Delegate, FieldIndex, FieldName + "_ptr"), FieldName)); }
/// <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")); }
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)); }
/// <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)); } }
public CatchHeader(IType ExceptionType, AtAddressEmitVariable ExceptionVariable) { this.ExceptionType = ExceptionType; this.exceptionVar = ExceptionVariable; }
/// <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)); }