Пример #1
0
        public void EmitUpdate(IExpr shared, IExpr expr, CodeGenerator generator)
        {
            EmitComment("Updating " + shared);
            if (shared is ITensor && shared is IShared)
            {
                var tensor = (ITensor)expr;
                var buff   = GetBuffer(tensor);
                if (buff != null && buff.IsShared && buff.Name == shared.Name && buff.References.Last() == expr)
                {
                    EmitComment($"{Scope.GetVar(expr)} is already in {shared.Name}");
                }
                else if (buff != null)
                {
                    EmitLine($"Copy({Scope.GetVar(expr)}, result: {GetShared((IShared)shared)});");
                }
                else
                {
                    EmitLine($"{GetShared((IShared)shared)} = {Scope.GetVar(expr)};");
                }
            }
            else if (shared is IShared)
            {
                EmitLine($"{GetShared((IShared)shared)} = {Scope.GetVar(expr)};");
            }
            else if (shared is Operators.Tensors.Slicing <float> )
            {
                var indexing = (Operators.Tensors.Slicing <float>)shared;
                this.CompileExpr((IExpr)indexing.Slices, generator);

                EmitLine($"{Scope.GetVar(indexing.x)}[{Scope.GetVar(indexing.Slices)}] = {Scope.GetVar(expr)};");
            }
            else
            {
                EmitLine($"{InlineCodeGenerator.GetCode(shared)} = {Scope.GetVar(expr)};");
            }
            DecCount(expr);
            EmitLine();
        }
Пример #2
0
        /// <summary>
        /// Generate code for an Elementwise.
        /// Will try to group cascading "Elementwise objects" into one.
        /// </summary>
        /// <returns>True if the input was actually an Elementwise operator.</returns>
        public virtual bool VisitElementwise <T>(Tensor <T> .Elementwise elementwise, Compiler compiler)
        {
            if (loopVariables.Count > 0)
            {
                foreach (var e in elementwise.Inputs)
                {
                    compiler.CompileExpr(e, this);
                }
                if (!elementwise.Inputs.All(e => compiler.Scope.Contains(e)))
                {
                    return(true);     // part of the expression was not reachable, exit (processed = true)
                }
            }

            var arguments = (elementwise.Vars, elementwise.Inputs).Zip().ToList();
            var expr      = ApplyLambdaAbstraction(elementwise.Abstraction, arguments, compiler);

            using (LoopInvariant(arguments.Select(_ => _.Item1)))
                compiler.CompileExpr(expr, this);

            foreach (var t in arguments)
            {
                compiler.CompileExpr(t.Item2, this);
            }
            if (!arguments.All(t => compiler.Scope.Contains(t.Item2)))
            {
                return(true);                                                         // at least one expression could not compile (possible during loop invariant code motion)
            }
            foreach (var t in arguments)
            {
                compiler.DecCount(t.Item2);
            }

            string lambda;

            using (compiler.CreateScope())
            {
                // TODO: Is it necessary to create new variable here ? Is it just about renaming them ?
                var locals = arguments.Select(arg => new Scalar <float> .Var("_" + compiler.Scope.GetVar(arg.Item2))).ToList();
                foreach (var local in locals)
                {
                    compiler.Scope.Declare(local, compiler);
                }

                IExpr target   = expr;
                var   bindings = arguments.Zip(locals, (a, l) => ((IVar)a.Item1, (IExpr)l)).ToArray();
                foreach (var binding in bindings)
                {
                    if (binding.Item1 == target)
                    {
                        target = binding.Item2;
                        break;
                    }
                }
                var body = CodeProcessor.Process(compiler, target, bindings);

                var vars = locals.Count == 1 ?
                           locals[0].ToString() :
                           "(" + string.Join(", ", locals) + ")";
                lambda = vars + " => " + body;

                foreach (var t in arguments)
                {
                    compiler.DecCount(t.Item1);
#if REF
                    if (compiler.GetCount(t.Item1) != 0)
                    {
                        throw new Exception("Lambda variable not decremented");
                    }
#endif
                }
            }

            var args = string.Join(", ", arguments.Select(t => compiler.Scope.GetVar(t.Item2)));
            var code = $"NN.Apply({args}, {lambda})";

            var buff = compiler.GetBuffer(elementwise);
            if (buff != null)
            {
                code = $"{code.Substring(0, code.Length - 1)}, result: {compiler.GetBufferName(buff)})";
            }

            code += compiler.OfShape(elementwise, this);

#if SMART
            // TODO: when reference-counting works
            if (elementwise.Name == null && compiler.GetCount(elementwise) == 1)
            {
                compiler.Scope.Declare(elementwise, compiler, code);
            }
            else
#endif
            {
                compiler.Scope.Declare(elementwise, compiler);

                string comment = null;
                if (compiler.Verbose)
                {
                    elementwise.Comment = elementwise.Comment ?? InlineCodeGenerator.GetCode(elementwise);
                    comment             = compiler.RefComment(elementwise, arguments.Select(arg => arg.Item2), elementwise.Comment);
                }

                compiler.EmitAssign(elementwise, code, comment);
            }
            return(true);
        }