[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); }
private JitCompiler(CpuConfig config, Type t_kernel, TypeBuilder t_xformed) { _config = config; _t_kernel = t_kernel; _m_kernel = _t_kernel.GetMethod("RunKernel", BF.All); ValidateInputParameters(); // todo. think how to support multiple methods: *Dims, *Idxes, synchronization points // todo. I'd even say that we should embed constants instead of Dims and cache such bodies between calls // todo. if some dimension is equal to 1, then strip off corresponding loop var lam = _m_kernel.Decompile(); _hir = lam.Body; _params = lam.Sig.Syms; _locals = lam.Body.LocalsRecursive(); _xhir = new Block(); _tids.Add("x", new Local("tid_x", typeof(int))); _tids.Add("y", new Local("tid_y", typeof(int))); _tids.Add("z", new Local("tid_z", typeof(int))); _xhir.Locals.AddElements(_tids.Values); InferLocalAllocationHints(); ReplicatePrivatelyAllocatedLocals(); LiftLocallyAllocatedLocals(); HoistGloballyAllocatedLocals(); _callsToSyncThreads = _hir.Family().OfType<Eval>().Where(eval => { var m1 = eval.InvokedMethod(); var syncapi_syncThreads = typeof(ISyncApi).GetMethod("SyncThreads"); return m1.Api() == syncapi_syncThreads; }).ToReadOnly(); TransformBlock(_hir, _xhir, false); // todo. currently we don't support debuggable IL // the latter implies correct PDB-mappings and working watch for replicated vars _config.EmitDebuggableIL.AssertFalse(); _t_xformed = t_xformed; _t_xformed.AddInterfaceImplementation(typeof(IBlockRunner)); _m_xformed = _t_xformed.DefineMethod("RunBlock", MA.Public, typeof(void), typeof(int3).MkArray()); _m_xformed.DefineParameter(1, ParmA.None, "blockIdx"); CompileTransformedHir(); }
public static Block DoRestoreTypeIs(Block hir) { if (hir.Family().OfType<TypeAs>().None()) return hir; else { return hir.Transform((Operator op) => { var is_rel = op.OperatorType.IsRelational(); if (is_rel) { var bin = op.AssertCast<BinaryOperator>(); var opt = bin.OperatorType; var needs_xform = bin.Lhs is TypeAs ^ bin.Rhs is TypeAs; if (needs_xform) { var type_as = bin.Lhs as TypeAs ?? bin.Rhs as TypeAs; var other = bin.Lhs == type_as ? bin.Rhs : bin.Lhs; other.AssertCast<Const>().AssertThat(c => c.Value == null); var pos = opt == OperatorType.NotEqual || opt == OperatorType.GreaterThan; var neg = opt == OperatorType.Equal || opt == OperatorType.LessThanOrEqual; (pos || neg).AssertTrue(); var type_is = new TypeIs(type_as.Type, type_as.Target) as Expression; return pos ? type_is : Operator.Negate(type_is); } else { return op.DefaultTransform(); } } else { return op.DefaultTransform(); } }).AssertCast<Block>(); } }
public static void DoInferLoopIters(Block hir) { foreach (var loop in hir.Family().OfType<Loop>()) { if (loop.Iter.IsNotEmpty()) { loop.Iter.RemoveElements(n => n == null); } else { if (loop.Init.IsNotEmpty()) { Func<Expression, bool> isLvalueOfLool = e => { if (e == null) { return false; } else if (e is Ref) { var @ref = e.AssertCast<Ref>(); var local = @ref == null ? null : @ref.Sym as Local; return local != null && loop.Locals.Contains(local); } else if (e is Slot) { var slot = e.AssertCast<Slot>(); var @ref = slot == null ? null : slot.This as Ref; var local = @ref == null ? null : @ref.Sym as Local; return local != null && loop.Locals.Contains(local); } else if (e is Apply) { var app = e.AssertCast<Apply>(); var callee = app == null ? null : app.Callee; var prop = callee as Prop; var @ref = prop == null ? null : prop.This as Ref; var local = @ref == null ? null : @ref.Sym as Local; return local != null && loop.Locals.Contains(local); } else { return false; } }; var lil = loop.Body.LastOrDefault() as Expression; var lilIsIter = false; if (lil is Assign) { var ass = lil.AssertCast<Assign>(); lilIsIter = isLvalueOfLool(ass.Lhs); } else if (lil is Operator) { var op = lil.AssertCast<Operator>(); if (op.OperatorType.IsAssign()) { lilIsIter = isLvalueOfLool(op.Args.First()); } } else if (lil is Eval) { var m = lil.InvokedMethod(); if (m != null) { var args = lil.InvocationArgs(); if (m.IsInstance() || m.IsExtension()) { lilIsIter = isLvalueOfLool(args.FirstOrDefault()); } else { lilIsIter = args.Any(isLvalueOfLool); } } } if (lilIsIter) { loop.Iter = new Block(); loop.Iter.Add(lil); loop.Body.Remove(lil); } } } } }