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)); }
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)); }
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(); }