// note. pattern #1: // * ref = atom // * read(ref) // conditions: // 1) ref is read only once after it had been assigned // 2) atom isn't reassigned before read(ref) takes place // 3) if ref is CF$XXXX then atom can be of any node type (not only an atom) // transformed into: // * read(atom) private static bool TryMatchPattern1(DfaHelper dfa, Expression atom) { var p1_ref = atom as Ref; if (p1_ref == null) return false; var p1_lastass = dfa.Writes(p1_ref).LastOrDefault(); if (p1_lastass == null) return false; var p1_ref_onlyread_afterass = dfa.Reads(p1_ref).SingleOrDefault2( r => dfa.ExecOrderOfStmt(r) >= dfa.ExecOrderOfStmt(p1_lastass)); if (p1_ref_onlyread_afterass == null) return false; var p1_atom = p1_lastass.Rhs; if (!p1_ref.Sym.Name.StartsWith("CF$") && !p1_ref.Sym.Name.StartsWith("CS$")) { if (!p1_atom.IsAtom()) return false; var p1_atom_reasses = dfa.Writes(p1_atom).Where(w => dfa.ExecOrderOfStmt(p1_lastass) <= dfa.ExecOrderOfStmt(w) && dfa.ExecOrderOfStmt(w) <= dfa.ExecOrderOfStmt(p1_ref_onlyread_afterass)); if (p1_atom_reasses.IsNotEmpty()) return false; } dfa.Remove(p1_lastass); var p1_ref_onlyread_stmt = p1_ref_onlyread_afterass.Stmt(); dfa.ReplaceRecursive(p1_ref_onlyread_stmt, p1_ref, p1_atom); return true; }
[DebuggerNonUserCode] private ExpressionExpander(Expression source, ExpansionContext ctx) { Source = source; Ctx = ctx; Stmts = new List<Node>(); Result = Expand(Source); }
// note. pattern #2: // * atom = atom op any // transformed into: // * atom [op=] any private static bool TryMatchPattern2(DfaHelper dfa, Expression atom) { var p2_atom = atom; foreach (var p2_ass in dfa.Writes(atom)) { if (!(p2_ass.Rhs is BinaryOperator)) continue; var binary = p2_ass.Rhs as BinaryOperator; if (!p2_atom.Equiv(binary.Lhs)) continue; var p2_opeq = p2_atom.CreateOpPreAssign(binary.OperatorType, binary.Rhs); if (p2_opeq == null) return false; dfa.Replace(p2_ass, p2_opeq); return true; } return false; }
public static BinaryOperator LeftShift(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.LeftShift, lhs, rhs); }
public static BinaryOperator LessThanOrEqual(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.LessThanOrEqual, lhs, rhs); }
public static BinaryOperator AddAssign(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.AddAssign, lhs, rhs); }
protected Slot(NodeType nodeType, MemberInfo member, Expression target) : base(nodeType, target) { Member = member; }
public static UnaryOperator Not(Expression target) { return new UnaryOperator(OperatorType.Not, target); }
private void Push(Expression expr) { var pp_expr = Filter(expr); _map.Add(pp_expr, _currentOp); var dbg = _currentOp.Source.DebugInfo; if (dbg != null) pp_expr.Family().Where(n => n != null).ForEach(n => n.Src = n.Src ?? dbg[_currentOp.Offset]); _stack.Push(pp_expr); }
// note. pattern #4 // <hoard> ref = atom // <op> atom = ref op any // <usage> read(ref) // conditions: // 1) exactly one read of ref // 2) <hoard> comes before <op> and <usage> // 3) <op> and <usage> may be ordered arbitrarily // 4) op is either an increment or a decrement // transformed into either: // * read(atom++), if op is an increment (use IsInc() method to test) // * read(atom--), if op is a decrement (use IsDec() method to test) private static bool TryMatchPattern4(DfaHelper dfa, Expression atom) { var p4_ref = atom as Ref; if (p4_ref == null) return false; var p4_usages = dfa.Usages(p4_ref); if (p4_usages.Count() != 3) return false; var p4_op = p4_usages.Select(u => u.Stmt()).OfType<Assign>().SingleOrDefault2(ass => { var bo = ass.Rhs as BinaryOperator; if (bo == null) return false; return bo.Lhs.Equiv(p4_ref); }); if (p4_op == null) return false; var p4_atom = p4_op.Lhs; if (!p4_atom.IsAtom()) return false; var p4_bop = p4_op.Rhs as BinaryOperator; if (p4_bop == null) return false; if (!p4_bop.Lhs.Equiv(p4_ref)) return false; var p4_optype = p4_bop.OperatorType; var p4_any = p4_bop.Rhs; var p4_hoard = p4_usages.First().Stmt(); var p4_hoard_template = new Assign(p4_ref, p4_atom); if (!p4_hoard.Equiv(p4_hoard_template)) return false; var p4_usage = p4_usages.Select(u => u.Stmt()).Except(p4_op).Last(); var p4_opeq = p4_atom.CreateOpPostAssign(p4_optype, p4_any); if (p4_opeq == null) return false; dfa.Remove(p4_hoard, p4_op); dfa.ReplaceRecursive(p4_usage, p4_ref, p4_opeq); return true; }
public static BinaryOperator MultiplyAssign(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.MultiplyAssign, lhs, rhs); }
public UnaryOperator(OperatorType operatorType, Expression target) : base(operatorType, target) { }
// note. pattern #3: // <op> ref = atom op any // <wb> atom = ref // <usage> read(ref) // conditions: // 1) exactly one read of ref // 2) <op> comes before <wb> and <usage> // 3) <wb> and <usage> may be ordered arbitrarily // transformed into either: // * read(++atom), if op is an increment (use IsInc() method to test) // * read(--atom), if op is a decrement (use IsDec() method to test) // * read(atom [op=] any), otherwise private static bool TryMatchPattern3(DfaHelper dfa, Expression atom) { var p3_ref = atom as Ref; if (p3_ref == null) return false; var p3_usages = dfa.Usages(p3_ref); if (p3_usages.Count() != 3) return false; var p3_op = p3_usages.First() as Assign; if (p3_op == null) return false; if (!p3_op.Lhs.Equiv(p3_ref)) return false; var p3_bop = p3_op.Rhs as BinaryOperator; if (p3_bop == null) return false; var p3_atom = p3_bop.Lhs; var p3_optype = p3_bop.OperatorType; var p3_any = p3_bop.Rhs; if (!p3_atom.IsAtom()) return false; var p3_usage2_stmt = p3_usages.Second().Stmt(); var p3_usage3_stmt = p3_usages.Third().Stmt(); Expression p3_wb, p3_usage; var p3_wb_template = new Assign(p3_atom, p3_ref); if (p3_usage2_stmt.Equiv(p3_wb_template)) { p3_wb = (Expression)p3_usage2_stmt; p3_usage = (Expression)p3_usage3_stmt; } else if (p3_usage3_stmt.Equiv(p3_wb_template)) { p3_wb = (Expression)p3_usage3_stmt; p3_usage = (Expression)p3_usage2_stmt; } else return false; var p3_opeq = p3_atom.CreateOpPreAssign(p3_optype, p3_any); if (p3_opeq == null) return false; dfa.Remove(p3_op, p3_wb); dfa.ReplaceRecursive(p3_usage, p3_ref, p3_opeq); return true; }
public BinaryOperator(OperatorType operatorType, Expression lhs, Expression rhs) : base(operatorType, lhs, rhs) { }
private static bool NeedsParenthesesInCSharp(this Expression child, Expression parent) { if (parent is Eval) parent = ((Eval)parent).Parent as Expression; if (child == null || parent == null) return false; var p_app = parent as Apply; if (p_app != null) { if (p_app.Callee == child) { return false; } else { var m = p_app.InvokedMethod(); if (m != null) { var reallySpecial = m.IsSpecialName && !m.IsConstructor && m.EnclosingProperty() == null; var childIsFirstArg = p_app.Args.FirstOrDefault() == child; var explicitThis = m.IsInstance() || m.IsExtension(); if (!reallySpecial && (!childIsFirstArg || !explicitThis)) return false; } else { var p = p_app.InvokedProperty(); if (p != null) { return false; } else { (p_app.Callee == null).AssertTrue(); return false; } } } } if (child is Apply) { var m = child.InvokedMethod(); if (m != null) { if (m.IsUserDefinedOperator()) { // todo. add support for op_UnaryPlus var op_type = (OperatorType)Enum.Parse(typeof(OperatorType), m.UserDefinedOperatorType()); var equiv = Operator.Create(op_type, ((Apply)child).Args); return equiv.NeedsParenthesesInCSharp(parent); } else if (m.IsUserDefinedCast()) { (m.Paramc() == 1).AssertTrue(); var targetType = m.Ret(); var source = ((Apply)child).Args.Single(); // todo. think about cases when we can omit the cast // and, thus, need other algorithm of determining // whether we need parentheses or not var equiv = new Convert(targetType, source); return equiv.NeedsParenthesesInCSharp(parent); } } } // heuristics: this makes prettyprints more readable // todo. some day think this over again // check out examples in Truesight.Playground\Decompiler\Reference // for more thinking material if (parent is Operator && child is Operator) { var p_op = ((Operator)parent).OperatorType; var c_op = ((Operator)child).OperatorType; if (c_op.IsRelational() && p_op.IsEquality()) return true; if (p_op == c_op) return false; if (c_op == OperatorType.PostDecrement || c_op == OperatorType.PostIncrement || c_op == OperatorType.PreDecrement || c_op == OperatorType.PreIncrement || c_op == OperatorType.Negate || c_op == OperatorType.Not) { return false; } if (p_op == OperatorType.AndAlso || p_op == OperatorType.OrElse) { return true; } } if (child is Operator) { if (child.CSharpPriority() == Operator.PreIncrement().CSharpPriority()) { return child.CSharpPriority() < parent.CSharpPriority(); } else { return child.CSharpPriority() <= parent.CSharpPriority(); } } else if (child is Assign) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is Addr) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is CollectionInit) { return false; } else if (child is Conditional) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is Const) { return false; } else if (child is Convert) { return child.CSharpPriority() <= parent.CSharpPriority() && !(parent is Convert); } else if (child is Deref) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is Slot) { return false; } else if (child is Loophole) { return false; } else if (child is ObjectInit) { return false; } else if (child is Ref) { return false; } else if (child is SizeOf) { return false; } else if (child is TypeAs) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is TypeIs) { return child.CSharpPriority() <= parent.CSharpPriority(); } else if (child is Default) { return false; } else if (child is Apply) { return false; } else if (child is Eval) { return false; } else if (child is Lambda) { return false; } else { throw AssertionHelper.Fail(); } }
// node postprocessors private Expression Filter(Expression expr) { return Filter((Node)expr).AssertCast<Expression>(); }
public static BinaryOperator NotEqual(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.NotEqual, lhs, rhs); }
private void TransformExpression(Expression e, Block xregion, bool insideThreadLoop) { var xe = TransformExpression(e, insideThreadLoop); if (xe != null) xregion.Add(xe); }
public static BinaryOperator Modulo(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.Modulo, lhs, rhs); }
public static UnaryOperator PostIncrement(Expression target) { return new UnaryOperator(OperatorType.PostIncrement, target); }
public static UnaryOperator Negate(Expression target) { return new UnaryOperator(OperatorType.Negate, target); }
public static BinaryOperator SubtractAssign(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.SubtractAssign, lhs, rhs); }
public static BinaryOperator OrElse(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.OrElse, lhs, rhs); }
private Expression TransformExpression(Expression e, bool insideThreadLoop) { var xe = e.Transform( (Eval eval) => { var m = eval.InvokedMethod(); var decl = m == null ? null : m.DeclaringType; while (decl != null && decl.DeclaringType != null) decl = decl.DeclaringType; return decl == typeof(Hints) ? null : eval.DefaultTransform(); }, (Fld fld) => { var isXyz = fld.Field.Name == "X" || fld.Field.Name == "Y" || fld.Field.Name == "Z"; if (isXyz) { var parent = fld.This as Prop; var p_api = (parent == null ? null : parent.Property).Api(); if (p_api != null && p_api.DeclaringType == typeof(IGridApi)) { if (p_api.Name == "BlockIdx") { return new Fld(fld.Field, new Ref(_blockIdx)); } else if (p_api.Name == "ThreadIdx") { return new Ref(_tids[fld.Field.Name.ToLower()]); } else { return fld.DefaultTransform(); } } else { return fld.DefaultTransform(); } } else { return (Node)fld.DefaultTransform(); } }, (Prop prop) => { var p_api = prop.Property.Api(); if (p_api != null && p_api.DeclaringType == typeof(IGridApi)) { // todo. support raw queries for *Idx properties return prop.DefaultTransform(); } else { return prop.DefaultTransform(); } }, (Assign ass) => { var @ref = ass.Lhs as Ref; var local = @ref == null ? null : @ref.Sym as Local; if (local != null) { if (Alloc(local) == allocPrivate && _needsReplication[local]) { insideThreadLoop.AssertTrue(); var r_local = _replicatedLocals[local]; var replica = new Eval(new Apply( new Lambda(r_local.Type.ArraySetter()), new Ref(r_local), new Ref(_tids["z"]), new Ref(_tids["y"]), new Ref(_tids["x"]), ass.Rhs.CurrentTransform())); return (Node)replica; } else { return ass.DefaultTransform(); } } else { return ass.DefaultTransform(); } }, (Ref @ref) => { var sym = (Sym)@ref.Sym; if (sym == _params.Single()) { return new Ref(_this); } else { var local = sym as Local; if (local != null) { if (Alloc(local) == allocPrivate && _needsReplication[local]) { insideThreadLoop.AssertTrue(); var r_local = _replicatedLocals[local]; var replica = new Eval(new Apply( new Lambda(r_local.Type.ArrayGetter()), new Ref(r_local), new Ref(_tids["z"]), new Ref(_tids["y"]), new Ref(_tids["x"]))); return (Node)replica; } else { return @ref.DefaultTransform(); } } else { return @ref.DefaultTransform(); } } }).AssertCast<Expression>(); return xe; }
public static BinaryOperator RightShiftAssign(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.RightShiftAssign, lhs, rhs); }
public static BinaryOperator Divide(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.Divide, lhs, rhs); }
public static BinaryOperator Xor(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.Xor, lhs, rhs); }
public static BinaryOperator Coalesce(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.Coalesce, lhs, rhs); }
public static BinaryOperator AndAlso(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.AndAlso, lhs, rhs); }
public static BinaryOperator GreaterThan(Expression lhs, Expression rhs) { return new BinaryOperator(OperatorType.GreaterThan, lhs, rhs); }