(sink:UOp)
| 5 | from tinygrad.helpers import prod, getenv, TUPLE_ORDER |
| 6 | |
| 7 | def linearize(sink:UOp) -> list[UOp]: |
| 8 | # this is a toposort with priority |
| 9 | lst = list(sink.toposort()) |
| 10 | out_degree:defaultdict[UOp, int] = defaultdict(int) |
| 11 | priorities:dict[UOp, tuple[int, int, Any]] = {} |
| 12 | |
| 13 | # get consumers and assign priorities |
| 14 | # NOTE: this requires the lst be locally toposorted |
| 15 | for u in reversed(lst): |
| 16 | for s in u.src: out_degree[s] += 1 |
| 17 | |
| 18 | # we place UOps with higher run_counts later |
| 19 | run_count = prod([int(r.vmax)+1 for r in u.ranges]) |
| 20 | |
| 21 | # simple priority override. this is all bottom up now, smaller numbers will be closer to the top |
| 22 | extra = None |
| 23 | match u.op: |
| 24 | # the order and placement of these defines is important |
| 25 | case Ops.PARAM: priority, extra = -20, u.arg |
| 26 | case Ops.DEFINE_VAR: priority, extra = -19, u.arg |
| 27 | case Ops.DEFINE_REG: priority = -18 |
| 28 | case Ops.DEFINE_LOCAL: priority = -17 |
| 29 | case Ops.LOAD: priority = -1 # place loads early |
| 30 | case Ops.STORE: priority = 1 # place stores late |
| 31 | case Ops.RANGE: priority = 5 # placing RANGE is good |
| 32 | case Ops.END: priority = -5 # placing END is bad |
| 33 | case _: priority = 0 # everything else has priority 0 |
| 34 | priorities[u] = (run_count, priority, extra) |
| 35 | |
| 36 | # number the uops in "ideal" order |
| 37 | nkey = {u:i for i,u in enumerate(sorted(lst, key=lambda x: priorities[x]+(x.tuplize if TUPLE_ORDER else ())))} |
| 38 | |
| 39 | # then force them to be toposorted in as close to the ideal order as possible |
| 40 | heap = [(-nkey[sink], sink)] |
| 41 | newlst = [] |
| 42 | while heap: |
| 43 | newlst.append(u:=heapq.heappop(heap)[1]) |
| 44 | for v in u.src: |
| 45 | out_degree[v] -= 1 |
| 46 | if out_degree[v] == 0: heapq.heappush(heap, (-nkey[v],v)) |
| 47 | newlst = newlst[::-1] |
| 48 | |
| 49 | if getenv("DEBUG_LINEARIZE"): |
| 50 | for i,u in enumerate(newlst): |
| 51 | print(f"{i:4d} {str(u.op):20s} {multirange_str(u.ranges, color=True, pad=10)} {priorities[u]}") |
| 52 | return newlst |
| 53 | |
| 54 | class CFGContext: |
| 55 | def __init__(self, sink:UOp): |
no test coverage detected
searching dependent graphs…