[DebuggerNonUserCode] public BlockExpander(Block source, ExpansionContext ctx) { Source = source; Ctx = ctx; Stmts = new Block(); ctx.Scope = Stmts; var cloned_locals = source.Locals.Select(l => l.DeepClone()); cloned_locals.ForEach(local => ctx.Scope.Locals.Add(local)); var is_root = Ctx.Parent == null || (Ctx.Parent.Stack.Count() != Ctx.Stack.Count()); if (is_root) RetLabel = new Label(); else RetLabel.AssertNotNull(); source.ForEach(Expand); if (is_root && Stmts.LastOrDefault() is Goto) Stmts.RemoveLast(); var gotos = Stmts.Family().OfType<Goto>().Where(@goto => @goto.LabelId == RetLabel.Id).ToReadOnly(); if (is_root && gotos.IsNotEmpty()) Stmts.Add(RetLabel); }
// todo. verify that init and iter can live outside the thread loop (when insideThreadLoop is false) private void TransformLoop(Loop loop, Block xregion, bool insideThreadLoop) { var x_init = new Block(); TransformBlock(loop.Init, x_init, true); var x_test = TransformExpression(loop.Test, insideThreadLoop); var x_body = new Block(); TransformBlock(loop.Body, x_body, insideThreadLoop); var x_iter = new Block(); TransformBlock(loop.Iter, x_iter, true); var x_loop = new Loop(x_test, x_body); x_loop.Locals.SetElements(loop.Locals); x_loop.Init = new Block(x_init.Children); x_loop.Iter = new Block(x_iter.Children); xregion.Add(x_loop); }
private void TransformExpression(Expression e, Block xregion, bool insideThreadLoop) { var xe = TransformExpression(e, insideThreadLoop); if (xe != null) xregion.Add(xe); }
private void TransformIf(If @if, Block xregion, bool insideThreadLoop) { var x_test = TransformExpression(@if.Test, insideThreadLoop); var x_iftrue = new Block(); TransformBlock(@if.IfTrue, x_iftrue, insideThreadLoop); var x_iffalse = new Block(); TransformBlock(@if.IfFalse, x_iffalse, insideThreadLoop); xregion.Add(new If(x_test, x_iftrue, x_iffalse)); }
private void TransformBlock(Block hir, Block xhir, bool insideThreadLoop) { if (hir == null) return; var deepFission = new List<Node>(); var regions = new List<ReadOnlyCollection<Node>>(); var curr_region = new List<Node>(); foreach (var stmt in hir) { if (_callsToSyncThreads.Contains(stmt as Eval)) { if (curr_region.IsNotEmpty()) regions.Add(curr_region.ToReadOnly()); curr_region = new List<Node>(); } else if (_callsToSyncThreads.Any(c => Set.Intersect(c.Hierarchy(), stmt.MkArray()).IsNotEmpty())) { if (curr_region.IsNotEmpty()) regions.Add(curr_region.ToReadOnly()); curr_region = new List<Node>(); deepFission.Add(stmt); regions.Add(stmt.MkArray().ToReadOnly()); } else { curr_region.Add(stmt); } } if (curr_region.IsNotEmpty()) regions.Add(curr_region.ToReadOnly()); curr_region = null; var privateLocals = hir.Locals.Where(l => Alloc(l) == allocPrivate).ToReadOnly(); var privateUsages = privateLocals.ToDictionary(l => l, l => regions.Where(r => r.UsagesOfLocal(l).IsNotEmpty()).ToReadOnly()); privateUsages.ForEach(kvp => { var needsReplication = kvp.Value.Count() > 1; _needsReplication[kvp.Key] = needsReplication; if (needsReplication) { _xhir.Insert(_lastIndex++, _replicatedInits[kvp.Key]); _xhir.Locals.Add(_replicatedLocals[kvp.Key]); } }); foreach (var region in regions) { var xregion = new Block(); var needsToBeWrapped = !deepFission.Contains(region.SingleOrDefault2()); var regionIsInsideThreadLoop = insideThreadLoop || needsToBeWrapped; foreach (var stmt in region) { if (stmt is Expression) { TransformExpression(((Expression)stmt), xregion, regionIsInsideThreadLoop); } else if (stmt is If) { TransformIf(((If)stmt), xregion, regionIsInsideThreadLoop); } else if (stmt is Loop) { TransformLoop(((Loop)stmt), xregion, regionIsInsideThreadLoop); } else { throw AssertionHelper.Fail(); } } if (needsToBeWrapped && !insideThreadLoop) { xhir.Add(new Loop { Init = new Block(new Assign(new Ref(_tids["z"]), new Const(0))), Test = Operator.LessThan(new Ref(_tids["z"]), new Fld(typeof(int3).GetField("Z"), new Prop(typeof(IGridApi).GetProperty("BlockDim"), new Ref(_this), true))), Body = new Block(new Loop { Init = new Block(new Assign(new Ref(_tids["y"]), new Const(0))), Test = Operator.LessThan(new Ref(_tids["y"]), new Fld(typeof(int3).GetField("Y"), new Prop(typeof(IGridApi).GetProperty("BlockDim"), new Ref(_this), true))), Body = new Block(new Loop { Init = new Block(new Assign(new Ref(_tids["x"]), new Const(0))), Test = Operator.LessThan(new Ref(_tids["x"]), new Fld(typeof(int3).GetField("X"), new Prop(typeof(IGridApi).GetProperty("BlockDim"), new Ref(_this), true))), Body = new Block(xregion.Children), Iter = new Block(Operator.PreIncrement(new Ref(_tids["x"]))), }), Iter = new Block(Operator.PreIncrement(new Ref(_tids["y"]))), }), Iter = new Block(Operator.PreIncrement(new Ref(_tids["z"]))), }); } else { xhir.AddElements(xregion.Children); } } var locals = hir.Locals.Except(_liftedLocals).ToReadOnly(); locals.ForEach(l => xhir.Locals.Add(l.DeepClone())); }