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