Основные выражения деревьев .Net запрещают указатели - PullRequest
0 голосов
/ 04 октября 2019

Я возился с внутренними качествами simnet .net 3.0 и видел несколько довольно значительных улучшений производительности. Я хотел попробовать написать переводчик выражений. Таким образом, вы можете определить базовое выражение с плавающей запятой, но тогда переводчик выдаст функцию, которая будет выполнять основные действия, такие как «Преобразование», «Сокращение», «Накопление» и т. Д.

Я написал кое-что, что, по моему мнению, должно работатьниже, но, очевидно, Expression.Variable не допускает типы указателей. Я заметил, что функция проверки имеет логическое значение allowPointer в трассировке стека. Есть ли способ построить дерево выражений с указателями и скомпилировать небезопасную функцию в ядре .net?

Приведенный ниже код просто пытается создать простую функцию добавления. Мне известно, что оно еще не обрабатывает входящее выражение.

Возникла исключительная ситуация: CLR / System.ArgumentException Произошло необработанное исключение типа 'System.ArgumentException' в System.Linq.Expressions.dll. : «Тип не должен быть указателем типа» в System.Dynamic.Utils.TypeUtils.ValidateType (Тип типа, String paramName, Boolean allowByRef, Boolean allowPointer) в System.Linq.Expressions.Expression.Validate (Тип тип, Boolean allowByRef)в System.Linq.Expressions.Expression.Variable (тип Type, имя строки) в MLNet.Math.VMExpression.Transform (Expression`1 expr) в /home/mltrainer/Desktop/mlnet/math/VM-Expression.cs:line67 на MLNet.Program.Main (String [] args) в /home/mltrainer/Desktop/mlnet/Program.cs:line 23

using System;
using VM.Core;
using System.Buffers;
using System.Linq.Expressions;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

namespace VM.Math
{
    public static class VMExpression
    {
        private static Expression BuildLessThanForLoop(Expression index,Expression end,Expression step,Func<Expression,Expression> block)
        {
            LabelTarget endLoop = Expression.Label();
            return Expression.Loop(Expression.Block(new Expression[]
            {
                Expression.IfThen(Expression.LessThan(index,end),Expression.Break(endLoop)),
                block(index),
                Expression.AddAssign(index,step)
            }),endLoop);              
        }

        private static Expression CalculateVectorLength(Expression arrayLength,ConstantExpression vectorLength)
        {
            return Expression.And(arrayLength,Expression.OnesComplement(Expression.Subtract(vectorLength,Expression.Constant(1))));
        }

        private static Expression LoadAlignedVector128Float(Expression vector,Expression ptr)
        {
            return Expression.Assign(vector,Expression.Call(typeof(Sse2).GetMethod("LoadAlignedVector128",new Type[] { typeof(float*) }),new Expression[] { ptr }));
        }

        private static Expression StoreAligned128Float(Expression vector,Expression ptr)
        {
            return Expression.Call(typeof(Sse2).GetMethod("StoreAligned",new Type[] { typeof(float*), typeof(Vector128<float>) }),new Expression[] { ptr, vector });            
        }
        private static Expression Index(Expression array,Expression index)
        {
             return Expression.ArrayIndex(array,new Expression[] { index });
        }

        private static Expression Add128Float(Expression vx, Expression vy)
        {
            return Expression.Call(typeof(Sse2).GetMethod("Add",new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }), new Expression[] { vx, vy });
        }

        private static Expression CreateAlignedArray(Expression count)
        {
            return Expression.New(typeof(AlignedFloatArray).GetConstructor(new Type[]{ typeof(int) }), new Expression[] { count });
        }

        public static unsafe Func<AlignedFloatArray,AlignedFloatArray,AlignedFloatArray> Transform(Expression<Func<float,float,float>> expr)
        {
            var paramX = Expression.Parameter(typeof(AlignedFloatArray),"x");
            var paramY = Expression.Parameter(typeof(AlignedFloatArray),"y");
            var parameters = new ParameterExpression[] { paramX, paramY };

            var result = Expression.Variable(typeof(AlignedFloatArray),"result");
            var memX = Expression.Variable(typeof(Memory<float>),"memX");
            var memY = Expression.Variable(typeof(Memory<float>),"memY");
            var memZ = Expression.Variable(typeof(Memory<float>),"memZ");

            var pinX = Expression.Variable(typeof(MemoryHandle),"pinX");
            var pinY = Expression.Variable(typeof(MemoryHandle),"pinY");
            var pinZ = Expression.Variable(typeof(MemoryHandle),"pinZ");

            var ptrX = Expression.Variable(typeof(float*),"ptrX");
            var ptrY = Expression.Variable(typeof(float*),"ptrY");
            var ptrZ =  Expression.Variable(typeof(float*),"ptrZ");

            var i = Expression.Variable(typeof(int),"i");
            var n = Expression.Variable(typeof(int),"n");
            var step = Expression.Constant(Vector128<float>.Count);
            var length = Expression.Variable(typeof(int),"length");
            var vx = Expression.Variable(typeof(Vector128<float>));
            var vy = Expression.Variable(typeof(Vector128<float>));

            var returnLabel = Expression.Label();

            var methodBlock = Expression.Block(parameters, new Expression[]
            {
                Expression.Assign(result,CreateAlignedArray(Expression.PropertyOrField(paramX,"Length"))),
                Expression.Assign(memX,Expression.Call(paramX,typeof(AlignedFloatArray).GetMethod("AsMemory"))),
                Expression.Assign(memY,Expression.Call(paramY,typeof(AlignedFloatArray).GetMethod("AsMemory"))),
                Expression.Assign(memZ,Expression.Call(result,typeof(AlignedFloatArray).GetMethod("AsMemory"))),
                Expression.Assign(pinX,Expression.Call(memX,typeof(Memory<float>).GetMethod("Pin"))),
                Expression.Assign(pinY,Expression.Call(memY,typeof(Memory<float>).GetMethod("Pin"))),
                Expression.Assign(pinZ,Expression.Call(memZ,typeof(Memory<float>).GetMethod("Pin"))),
                Expression.Assign(ptrX,Expression.Convert(Expression.PropertyOrField(pinX,"Pointer"),typeof(float*))),
                Expression.Assign(ptrY,Expression.Convert(Expression.PropertyOrField(pinY,"Pointer"),typeof(float*))),
                Expression.Assign(ptrZ,Expression.Convert(Expression.PropertyOrField(pinZ,"Pointer"),typeof(float*))),
                Expression.TryFinally(Expression.Block(new Expression[]
                {
                    Expression.Assign(i,Expression.Constant(0)),
                    Expression.Assign(length,Expression.PropertyOrField(paramX,"Length")),
                    Expression.Assign(n,CalculateVectorLength(length,step)), 
                    Expression.IfThen(Expression.GreaterThanOrEqual(n,step),Expression.Block(new Expression[]
                    {
                        BuildLessThanForLoop(i,n,step,(index) => {
                            return Expression.Block(new Expression[]
                            {
                                LoadAlignedVector128Float(vx,ptrX),
                                LoadAlignedVector128Float(vy,ptrY),
                                StoreAligned128Float(ptrZ,Add128Float(vx,vy))
                            });
                        })
                    })),
                    BuildLessThanForLoop(i,length,Expression.Constant(1),(index) =>
                    {
                        return Expression.Block(new Expression[]
                        {
                          Expression.Assign(Index(ptrZ,index),Expression.Add(Index(ptrX,index),Index(ptrY,index)))
                        });
                    }),
                    Expression.Return(returnLabel,result)
                }),
                Expression.Block(new Expression[]
                {
                    Expression.Call(pinX,typeof(MemoryHandle).GetMethod("Dispose")),
                    Expression.Call(pinY,typeof(MemoryHandle).GetMethod("Dispose")),
                    Expression.Call(pinZ,typeof(MemoryHandle).GetMethod("Dispose"))
                }))
            });

           return (Func<AlignedFloatArray,AlignedFloatArray,AlignedFloatArray>)Expression.Lambda(methodBlock,parameters).Compile(false);
        }        
    }
}
...