Example #1
0
        private Expression VisitMethodCallCore(MethodCallExpression node)
        {
            var i           = Expression.Parameter(typeof(int), "i");
            var retval      = Expression.Parameter(typeof(T[]), "retval");
            var arguments   = node.Arguments.Select((_, i) => Expression.Parameter(typeof(Vector <T>), $"_{i}")).ToArray();
            var vectorCount = Expression.Property(null, MemberTable._Vector <T> .Count);

            var block = new List <Expression>();

            block.Add(Expression.Assign(
                          retval,
                          Expression.NewArrayBounds(typeof(T), vectorCount)
                          ));
            block.AddRange(node.Arguments.Zip(arguments, (arge, argv) =>
                                              Expression.Assign(argv, Visit(arge))
                                              ));
            block.Add(ExpressionEx.For(
                          Expression.Assign(i, Expression.Constant(0)),
                          Expression.LessThan(i, vectorCount),
                          Expression.PreIncrementAssign(i),
                          Expression.Assign(
                              Expression.ArrayAccess(retval, i),
                              Expression.Call(
                                  node.Object,
                                  node.Method,
                                  arguments.Select(arg => Expression.Property(arg, MemberTable._Vector <T> .Item, i))
                                  )
                              )
                          ));
            block.Add(Expression.New(MemberTable._Vector <T> .ArrayConstructor, retval));

            return(Expression.Block(
                       new ParameterExpression[] { i, retval }.Concat(arguments),
                       block
                       ));
        }
        private static TDelegate Simdize <T, TDelegate>(LambdaExpression expr)
            where T : unmanaged
            where TDelegate : Delegate
        {
            if (_cache.TryGetValue(expr, out var value))
            {
                return((TDelegate)value);
            }

            var simdVisitor = new SimdVisitor <T>(expr);
            var simdBody    = simdVisitor.Visit(expr.Body);

            var i   = Expr.Parameter(typeof(int), "i");
            var len = Expr.Parameter(typeof(int), "len");

            var xMemories    = expr.Parameters.Select(p => Expr.Parameter(typeof(ReadOnlyMemory <T>), p.Name)).ToArray();
            var resultMemory = Expr.Parameter(typeof(Memory <T>), "result");

            var xSpans     = xMemories.Select(p => Expr.Variable(typeof(ReadOnlySpan <T>), $"{p.Name}Span")).ToArray();
            var resultSpan = Expr.Variable(typeof(Span <T>), "resultSpan");

            var xVecSpans     = xMemories.Select(p => Expr.Variable(typeof(ReadOnlySpan <Vector <T> >), $"{p.Name}VecSpan")).ToArray();
            var resultVecSpan = Expr.Variable(typeof(Span <Vector <T> >), "resultVecSpan");

            var xSpanGetters    = xSpans.Select(p => Expr.Call(null, MemberTable._ReadOnlySpan <T> .GetItem, p, i)).ToArray();
            var xVecSpanGetters = xVecSpans.Select(p => Expr.Call(null, MemberTable._ReadOnlySpan <Vector <T> > .GetItem, p, i)).ToArray();

            var exprCall = new LambdaArgsVisitor(expr.Parameters.Zip(xSpanGetters).ToDictionary(tpl => tpl.Item1, tpl => (Expr)tpl.Item2)).Visit(expr.Body);
            var simdCall = new LambdaArgsVisitor(simdVisitor.NewArguments.Zip(xVecSpanGetters).ToDictionary(tpl => tpl.Item1, tpl => (Expr)tpl.Item2)).Visit(simdBody);

            var resultSpanSetter    = Expr.Call(null, MemberTable._Span <T> .SetItem, resultSpan, i, exprCall);
            var resultVecSpanSetter = Expr.Call(null, MemberTable._Span <Vector <T> > .SetItem, resultVecSpan, i, simdCall);

            var parameters = xMemories.Concat(new[] { resultMemory });
            var variables  = xSpans.Concat(xVecSpans).Concat(new[] { i, len, resultSpan, resultVecSpan });

            var block = new List <Expr>();

            //  xSpan = xMemory.Span;
            block.AddRange(xMemories.Zip(xSpans, (memory, span) =>
                                         Expr.Assign(
                                             span,
                                             Expr.Property(memory, MemberTable._ReadOnlyMemory <T> .Span)
                                             )
                                         ));

            //  xVecSpan = MemoryMarshal.Cast<T, Vector<T>>(xSpan);
            block.AddRange(xSpans.Zip(xVecSpans, (span, vSpan) =>
                                      Expr.Assign(
                                          vSpan,
                                          Expr.Call(null, MemberTable._MemoryMarshal.Cast <T, Vector <T> > .ForReadOnlySpan, span)
                                          )
                                      ));

            //  resultSpan = resultMemory.Span;
            block.Add(
                Expr.Assign(
                    resultSpan,
                    Expr.Property(resultMemory, MemberTable._Memory <T> .Span)
                    )
                );

            //  resultVecSpan = MemoryMarshal.Cast<T, Vector<T>>(resultSpan);
            block.Add(
                Expr.Assign(
                    resultVecSpan,
                    Expr.Call(null, MemberTable._MemoryMarshal.Cast <T, Vector <T> > .ForSpan, resultSpan)
                    )
                );

            //  for(i = 0, len = resultVecSpan.Length & ~0b1111; i < len; )
            //  {
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x0
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x1
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x2
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x3
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x4
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x5
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x6
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x7
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x8
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x9
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xA
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xB
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xC
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xD
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xE
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0xF
            //  }
            block.Add(
                ExpressionEx.For(
                    Expr.Block(
                        Expr.Assign(i, Expr.Constant(0)),
                        Expr.Assign(
                            len,
                            Expr.And(Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length), Expr.Constant(~0b1111))
                            )
                        ),
                    Expr.LessThan(i, len),
                    Expr.Empty(),
                    Expr.Block(
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x0
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x1
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x2
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x3
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x4
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x5
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x6
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x7
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x8
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x9
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0xA
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0xB
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0xC
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0xD
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0xE
                        resultVecSpanSetter, Expr.PreIncrementAssign(i)   // 0xF
                        )
                    )
                );

            //  if(i < (resultVecSpan.Length & ~0b111))
            //  {
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x0
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x1
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x2
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x3
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x4
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x5
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x6
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x7
            //  }
            block.Add(
                Expr.IfThen(
                    Expr.LessThan(
                        i,
                        Expr.And(Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length), Expr.Constant(~0b111))
                        ),
                    Expr.Block(
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x0
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x1
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x2
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x3
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x4
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x5
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x6
                        resultVecSpanSetter, Expr.PreIncrementAssign(i)   // 0x7
                        )
                    )
                );

            //  if(i < (resultVecSpan.Length & ~0b11))
            //  {
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x0
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x1
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x2
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x3
            //  }
            block.Add(
                Expr.IfThen(
                    Expr.LessThan(
                        i,
                        Expr.And(Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length), Expr.Constant(~0b11))
                        ),
                    Expr.Block(
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x0
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x1
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x2
                        resultVecSpanSetter, Expr.PreIncrementAssign(i)   // 0x3
                        )
                    )
                );

            //  if(i < (resultVecSpan.Length & ~0b1))
            //  {
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x0
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x1
            //  }
            block.Add(
                Expr.IfThen(
                    Expr.LessThan(
                        i,
                        Expr.And(Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length), Expr.Constant(~0b1))
                        ),
                    Expr.Block(
                        resultVecSpanSetter, Expr.PreIncrementAssign(i),  // 0x0
                        resultVecSpanSetter, Expr.PreIncrementAssign(i)   // 0x1
                        )
                    )
                );

            //  if(i < resultVecSpan.Length)
            //  {
            //      resultVecSpan[i] = simdCall(xVecSpan[i], ...); ++i;  // 0x0
            //  }
            block.Add(
                Expr.IfThen(
                    Expr.LessThan(
                        i,
                        Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length)
                        ),
                    Expr.Block(
                        resultVecSpanSetter, Expr.PreIncrementAssign(i)   // 0x0
                        )
                    )
                );

            //  for(i = Vector<T>.Count * resultVecSpan.Length; i < resultSpan.Length; )
            //  {
            //      resultSpan[i] = exprCall(xSpan[i], ...); ++i;
            //  }
            block.Add(
                ExpressionEx.For(
                    Expr.Assign(
                        i,
                        Expr.Multiply(
                            Expr.Constant(Vector <T> .Count),
                            Expr.Property(resultVecSpan, MemberTable._Span <Vector <T> > .Length)
                            )
                        ),
                    Expr.LessThan(i, Expr.Property(resultSpan, MemberTable._Span <T> .Length)),
                    Expr.Empty(),
                    Expr.Block(
                        resultSpanSetter, Expr.PreIncrementAssign(i)
                        )
                    )
                );
            var retval = Expr.Lambda <TDelegate>(Expr.Block(variables, block), parameters).Compile();

            _cache.TryAdd(expr, retval);
            return(retval);
        }