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