Compare commits

...
Author SHA1 Message Date
George HotzandGitHub f34efbe9f3 Merge branch 'master' into simpler_image 2026-06-24 16:53:31 -07:00
geohot 0f40b9c3b5 ish 2026-06-24 16:14:15 -07:00
geohot 06bd987dcb fix half 2026-06-24 15:43:05 -07:00
geohot 1cbe0ba1f2 handle demote to non image 2026-06-24 15:16:00 -07:00
geohot 548154c8f2 image index 2026-06-24 14:34:44 -07:00
geohot 2d1d91dd99 fix indexing 2026-06-24 14:27:34 -07:00
geohot 1da09eb82d //4 2026-06-24 14:07:01 -07:00
geohot 5825ffbbcf simpler image (no stupid ai) 2026-06-24 14:03:41 -07:00
3 changed files with 27 additions and 6 deletions
+17 -2
View File
@@ -4,6 +4,7 @@ import itertools
from tinygrad.helpers import DISABLE_FAST_IDIV, TRANSCENDENTAL, SPEC, DEBUG, VIZ, IMAGE, NOOPT, EMULATED_DTYPES, NOLOCALS, USE_TC
from tinygrad.helpers import ALLOW_TF32, TracingKey, Context, panic
from tinygrad.uop.ops import PatternMatcher, graph_rewrite, UOp, pm_lower_index_dtype, Ops, UPat, track_rewrites, KernelInfo, ProgramInfo, GroupOp
from tinygrad.uop.ops import shape_to_shape_arg
from tinygrad.uop.render import pyrender
from tinygrad.uop.spec import type_verify, spec_tensor, spec_program
from tinygrad.renderer import Renderer, Estimates
@@ -57,6 +58,16 @@ pm_no_weakints = PatternMatcher([
(UPat(GroupOp.All, dtype=dtypes.weakint, name="x"), lambda x: x.replace(dtype=dtypes.int))
])
pm_fix_image_shrink = PatternMatcher([
# proper image index
(UPat(Ops.SHRINK, src=(UPat(Ops.RESHAPE, src=(UPat(Ops.PARAM, name="img"), UPat())), UPat(name="idx"), UPat()), name="out"),
lambda img,out,idx: img.reshape(-1, 4).index(idx.src[0]//4) if len(img.shape) == 3 and out.shape == (4,) else None),
# demote this to non image
(UPat(Ops.INDEX, src=(UPat(Ops.RESHAPE, src=(UPat(Ops.PARAM, name="img"), UPat())), UPat(name="idx")), name="out"),
lambda img,out,idx: img.replace(src=(shape_to_shape_arg((img.max_numel(),)),),
dtype=dtypes.half if img.dtype.itemsize == 2 else dtypes.float).index(idx) if out.shape == () else None)
])+pm_mops
def full_rewrite_to_sink(ast:UOp, ren:Renderer, optimize:bool=True) -> UOp:
if VIZ: graph_rewrite(ast, PatternMatcher([]), name="View Base AST")
if DEBUG >= 5: print(pyrender(ast))
@@ -104,8 +115,8 @@ def full_rewrite_to_sink(ast:UOp, ren:Renderer, optimize:bool=True) -> UOp:
sink = graph_rewrite(sink, pm_add_loads+pm_remove_invalid, name="** add loads (code)")
# create image buffers
if IMAGE and ren.target.device in {"QCOM", "CL", "PYTHON", "NULL"}:
sink = graph_rewrite(sink, pm_make_images, name="create image buffers", bottom_up=True, ctx=ren.target.arch)
#if IMAGE and ren.target.device in {"QCOM", "CL", "PYTHON", "NULL"}:
# sink = graph_rewrite(sink, pm_make_images, name="create image buffers", bottom_up=True, ctx=ren.target.arch)
# devectorize
sink = graph_rewrite(sink, sym+devectorize_alu+devectorize_buf_and_index+load_store_folding+correct_load_store+load_store_indexing,
@@ -127,6 +138,10 @@ def full_rewrite_to_sink(ast:UOp, ren:Renderer, optimize:bool=True) -> UOp:
# do memory coalesing (late)
sink = memory_coalesing(sink, ren)
# image fixup
#if IMAGE and ren.target.device in {"QCOM", "CL", "PYTHON", "NULL"}:
# sink = graph_rewrite(sink, pm_fix_image_shrink, name="fix image shrink")
# instruction selection decompositions
pm_decomp = pm_decomp+\
get_late_rewrite_patterns(supported_ops, bool(DISABLE_FAST_IDIV))+\
+9 -3
View File
@@ -3,17 +3,20 @@ import itertools
from collections import defaultdict
from tinygrad.dtype import dtypes, AddrSpace, Invalid, ImageDType
from tinygrad.uop.ops import UOp, Ops
from tinygrad.helpers import getenv
from tinygrad.helpers import getenv, IMAGE
from tinygrad.renderer import Renderer
# image now lives here
def memory_coalesing(sink:UOp, ctx:Renderer) -> UOp:
if getenv("DMC"): return sink
using_image = IMAGE and ctx.target.device in {"QCOM", "CL", "PYTHON", "NULL"}
# collect
memory: defaultdict[tuple[Ops, UOp, Any, Any], dict[int, list[UOp]]] = defaultdict(dict)
for u in sink.toposort():
# TODO: this should handle images too, it's just memory coalesing
if u.op in {Ops.LOAD, Ops.STORE} and not isinstance(u.src[0].src[0].dtype, ImageDType):
if u.op in {Ops.LOAD, Ops.STORE}:
assert len(u.src) == (2 if u.op is Ops.STORE else 1), "memory coalesing does not support gated loads/stores"
if u.src[0].op is not Ops.INDEX: continue
buf, idx_u = u.src[0].src
@@ -44,7 +47,7 @@ def memory_coalesing(sink:UOp, ctx:Renderer) -> UOp:
lengths = [4]
elif ctx is not None and ctx.supports_float4:
# TODO: a better way to get this than ctx
lengths = [8,4,2] if buf.dtype.base == dtypes.half and getenv("ALLOW_HALF8") else [4,2]
lengths = [8,4,2] if buf.dtype.base == dtypes.half and getenv("ALLOW_HALF8") and not using_image else [4,2]
lengths.append(1) # worst case, it's not folded
# do the grouping
grouped_offsets = [[x for _,x in group] for _,group in itertools.groupby(enumerate(sorted(offsets.keys())), lambda x: x[1]-x[0])]
@@ -53,6 +56,9 @@ def memory_coalesing(sink:UOp, ctx:Renderer) -> UOp:
offset = (base+full_grp[0]) if isinstance(base, UOp) else UOp.const(dtypes.int, full_grp[0])
length = [l for l in lengths if l <= len(full_grp) and (not must_divide or offset.divides(l) is not None)][0]
grp = full_grp[:length]
if len(grp) == 4 and using_image:
print("IMAGE OPTION")
pass
idx = buf._mop(Ops.SHRINK, arg=[(offset, len(grp))]) if len(grp) > 1 else buf.index(offset)
if op == Ops.STORE:
datas = []
+1 -1
View File
@@ -172,7 +172,7 @@ def split_load_store(ctx:Renderer|None, ls:UOp, idx:UOp):
lengths = []
must_divide = True
# TODO: this belongs in coalese
if isinstance(buf.dtype, ImageDType): lengths = [4]
#if isinstance(buf.dtype, ImageDType): lengths = [4]
lengths.append(1) # worst case, it's not folded
# filter fold lengths that don't divide