mirror of
https://github.com/tinygrad/tinygrad.git
synced 2026-08-17 17:38:26 +00:00
Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4e1b93225 | ||
|
|
4a31c319b3 | ||
|
|
59081645f7 | ||
|
|
6e57905c6d | ||
|
|
40606c60b0 | ||
|
|
80986321eb | ||
|
|
bd263cbcb0 | ||
|
|
2e41472b02 | ||
|
|
ac641f7b10 | ||
|
|
226c59fa5a | ||
|
|
3bbfcbccde | ||
|
|
78a56b3461 | ||
|
|
b5ac4501d4 | ||
|
|
038d3bc295 | ||
|
|
4b223c820a | ||
|
|
528e285d81 | ||
|
|
cd3dc67636 | ||
|
|
b19a8963c3 | ||
|
|
ec10e00cf5 | ||
|
|
d3aa38ad4a | ||
|
|
6e41040e91 | ||
|
|
6b3d9d6663 | ||
|
|
0ece218588 | ||
|
|
feb12685f2 |
@@ -445,10 +445,10 @@ class TestUOpGraph(unittest.TestCase):
|
|||||||
with Context(IGNORE_OOB=0):
|
with Context(IGNORE_OOB=0):
|
||||||
glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), src=(), arg=0)
|
glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), src=(), arg=0)
|
||||||
v = Variable("v", 0, 20)
|
v = Variable("v", 0, 20)
|
||||||
st0 = UOp(Ops.STORE, dtypes.void, src=(glbl0.index(v), UOp.const(dtypes.int, 0), UOp(Ops.IF, src=(v<16,))))
|
st0 = UOp(Ops.STORE, dtypes.void, src=(glbl0.index(v, v<16), UOp.const(dtypes.int, 0)))
|
||||||
to_uops_list([st0])
|
to_uops_list([st0])
|
||||||
|
|
||||||
st1 = UOp(Ops.STORE, dtypes.void, (glbl0.index(v), v, v<20))
|
st1 = UOp(Ops.STORE, dtypes.void, (glbl0.index(v, v<20), v))
|
||||||
with self.assertRaises(RuntimeError): to_uops_list([st1])
|
with self.assertRaises(RuntimeError): to_uops_list([st1])
|
||||||
|
|
||||||
def test_in_bounds_access_gated_local(self):
|
def test_in_bounds_access_gated_local(self):
|
||||||
@@ -463,7 +463,7 @@ class TestUOpGraph(unittest.TestCase):
|
|||||||
|
|
||||||
gate = (gidx<400) & (lidx<8)
|
gate = (gidx<400) & (lidx<8)
|
||||||
|
|
||||||
local_store = UOp(Ops.STORE, dtypes.void, (sbuf.index(lidx), UOp.const(dtypes.uint, 1), UOp(Ops.IF, src=(lidx<8,))))
|
local_store = UOp(Ops.STORE, dtypes.void, (sbuf.index(lidx, lidx<8), UOp.const(dtypes.uint, 1)))
|
||||||
|
|
||||||
barrier = UOp(Ops.BARRIER, dtypes.void, (local_store,))
|
barrier = UOp(Ops.BARRIER, dtypes.void, (local_store,))
|
||||||
if_barrier = UOp(Ops.IF, dtypes.void, (gate, barrier))
|
if_barrier = UOp(Ops.IF, dtypes.void, (gate, barrier))
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def shape_to_idx(s, axis_types, start=0):
|
|||||||
|
|
||||||
def get_index(ast:UOp) -> IndexContext:
|
def get_index(ast:UOp) -> IndexContext:
|
||||||
axis_types = ast.arg.axis_types if isinstance(ast.arg, KernelInfo) else ()
|
axis_types = ast.arg.axis_types if isinstance(ast.arg, KernelInfo) else ()
|
||||||
if len(ast.full_shape) != len(axis_types):
|
if len(ast.full_shape) != len(axis_types) and ast.st is not None:
|
||||||
axis_types = tuple([AxisType.REDUCE if resolve(s != fs) else AxisType.LOOP for s,fs in zip(ast.shape, ast.full_shape)])
|
axis_types = tuple([AxisType.REDUCE if resolve(s != fs) else AxisType.LOOP for s,fs in zip(ast.shape, ast.full_shape)])
|
||||||
return IndexContext(axis_types, [], 0)
|
return IndexContext(axis_types, [], 0)
|
||||||
|
|
||||||
|
|||||||
@@ -22,17 +22,11 @@ def get_optimized_ast(ast:UOp, renderer:Renderer) -> UOp|None:
|
|||||||
# no shape, no opt
|
# no shape, no opt
|
||||||
if ast.src[0].st is None: return None
|
if ast.src[0].st is None: return None
|
||||||
new_arg = ast.arg
|
new_arg = ast.arg
|
||||||
if new_arg is None:
|
if new_arg is None and not NOOPT and not BEAM:
|
||||||
k = Kernel(ast, opts=renderer)
|
k = Kernel(ast, opts=renderer)
|
||||||
if not NOOPT:
|
if not k.apply_tensor_cores(USE_TC.value): k.apply_opts(hand_coded_optimizations(k))
|
||||||
if not k.apply_tensor_cores(USE_TC.value): k.apply_opts(hand_coded_optimizations(k))
|
|
||||||
if BEAM >= 1:
|
|
||||||
from tinygrad.codegen.opt.search import beam_search, bufs_from_lin
|
|
||||||
kb = Kernel(ast, opts=renderer)
|
|
||||||
rawbufs = bufs_from_lin(kb, allocate=False)
|
|
||||||
k = beam_search(kb, rawbufs, BEAM.value, bool(getenv("BEAM_ESTIMATE", 1)))
|
|
||||||
new_arg = KernelInfo(opts_to_apply=tuple(k.applied_opts))
|
new_arg = KernelInfo(opts_to_apply=tuple(k.applied_opts))
|
||||||
elif len(new_arg.applied_opts): return None
|
elif new_arg is not None and len(new_arg.applied_opts): return None
|
||||||
return Kernel(ast.replace(arg=None), opts=renderer).get_optimized_ast().replace(arg=new_arg)
|
return Kernel(ast.replace(arg=None), opts=renderer).get_optimized_ast().replace(arg=new_arg)
|
||||||
|
|
||||||
pm_get_optimization = PatternMatcher([
|
pm_get_optimization = PatternMatcher([
|
||||||
|
|||||||
@@ -92,10 +92,6 @@ class Kernel:
|
|||||||
global_loops = AxisType.GLOBAL if self.opts.has_local else AxisType.LOOP
|
global_loops = AxisType.GLOBAL if self.opts.has_local else AxisType.LOOP
|
||||||
self.axis_types: list[AxisType] = [AxisType.REDUCE if resolve(x!=y) else global_loops for x,y in zip(self.output_shape, self.full_shape)]
|
self.axis_types: list[AxisType] = [AxisType.REDUCE if resolve(x!=y) else global_loops for x,y in zip(self.output_shape, self.full_shape)]
|
||||||
|
|
||||||
# confirm all reduce axes are at the end
|
|
||||||
if (final_reduces := [x for x in self.axis_types if x == AxisType.REDUCE]) and final_reduces != self.axis_types[-len(final_reduces):]:
|
|
||||||
raise RuntimeError(f"reduces are not at the end of the shape {self.full_shape} -> {self.output_shape}")
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
ret = type(self).__new__(type(self))
|
ret = type(self).__new__(type(self))
|
||||||
|
|
||||||
@@ -449,6 +445,7 @@ class Kernel:
|
|||||||
def shape_str_to_axis(self, nms:list[str]) -> tuple[int, ...]: return tuple([self.shape_str().index(x) for x in nms])
|
def shape_str_to_axis(self, nms:list[str]) -> tuple[int, ...]: return tuple([self.shape_str().index(x) for x in nms])
|
||||||
|
|
||||||
def get_optimized_ast(self, name_override:str|None=None) -> UOp:
|
def get_optimized_ast(self, name_override:str|None=None) -> UOp:
|
||||||
|
if self.applied_opts: raise RuntimeError("not supported")
|
||||||
@functools.cache
|
@functools.cache
|
||||||
def fixup_ast(op:UOp) -> UOp:
|
def fixup_ast(op:UOp) -> UOp:
|
||||||
ret = op.replace(src=tuple(fixup_ast(x) for x in op.src)) # noqa: F821
|
ret = op.replace(src=tuple(fixup_ast(x) for x in op.src)) # noqa: F821
|
||||||
|
|||||||
@@ -1,18 +1,197 @@
|
|||||||
from dataclasses import replace
|
import math, itertools
|
||||||
from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, KernelInfo
|
from tinygrad.dtype import AddrSpace
|
||||||
from tinygrad.helpers import colored
|
from tinygrad.uop.ops import UOp, Ops, sint, ssimplify, AxisType, KernelInfo, PatternMatcher, UPat, graph_rewrite
|
||||||
from tinygrad.codegen.opt.kernel import axis_colors
|
from tinygrad.helpers import DEBUG, BEAM, getenv
|
||||||
|
from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps, KernelOptError
|
||||||
|
from tinygrad.renderer import Renderer
|
||||||
|
from tinygrad.dtype import dtypes
|
||||||
|
from tinygrad.device import Buffer
|
||||||
|
|
||||||
def rename_sink(s:UOp):
|
def flatten_range(r:UOp):
|
||||||
if s.arg is not None and s.arg.name != "test": return None
|
off = 2 if r.op is Ops.STORE else 1
|
||||||
|
rngs = r.src[off:]
|
||||||
|
if not len(rngs): return None
|
||||||
|
new_rngs = [x for x in UOp.sink(*rngs).toposort() if x.op is Ops.RANGE]
|
||||||
|
return r.replace(src=r.src[:off]+tuple(new_rngs))
|
||||||
|
|
||||||
# get all ranges (sorted)
|
pm_flatten_range = PatternMatcher([
|
||||||
rngs = sorted([u for u in s.parents if u.op is Ops.RANGE], key=lambda x: x.arg[0:-1])
|
# real ranges only
|
||||||
|
(UPat((Ops.REDUCE, Ops.STORE), name="r"), flatten_range),
|
||||||
|
])
|
||||||
|
|
||||||
# add name to kernel
|
class RKernel(Kernel):
|
||||||
name = "k" + colored('_', 'BLACK').join(['']+[colored(x.src[0].render(), axis_colors[x.arg[-1]]) for x in rngs])
|
def __init__(self, ast:UOp, opts:Renderer|None=None):
|
||||||
return s.replace(arg=KernelInfo(name=name) if s.arg is None else replace(s.arg, name=name))
|
self.rng = sorted([u for u in ast.toposort() if u.op is Ops.RANGE and u.vmax > 0], key=lambda x: x.arg)
|
||||||
|
super().__init__(ast, opts)
|
||||||
|
self.sts.clear()
|
||||||
|
|
||||||
pm_postrange_opt = PatternMatcher([
|
# convert LOOP to GLOBAL
|
||||||
(UPat(Ops.SINK, name="s"), rename_sink),
|
self.replaces = {}
|
||||||
|
if self.opts.has_local:
|
||||||
|
store_rngs = self.ast.src[0].src[2:]
|
||||||
|
|
||||||
|
# filter any not in local stores
|
||||||
|
local_store_rngs = [x.ranges for x in self.ast.toposort() if (x.op is Ops.STORE and x.src[0].dtype.addrspace == AddrSpace.LOCAL) \
|
||||||
|
or (x.op is Ops.BUFFERIZE and x.arg == AddrSpace.LOCAL)]
|
||||||
|
for ls in local_store_rngs: store_rngs = tuple([x for x in store_rngs if x in ls])
|
||||||
|
|
||||||
|
store_rng = [x for x in UOp.sink(*store_rngs).toposort() if x.op is Ops.RANGE] if store_rngs else []
|
||||||
|
rng = [x.replace(arg=(x.arg[0], AxisType.GLOBAL)) if x.arg[1] == AxisType.LOOP and x in store_rng else x for x in self.rng]
|
||||||
|
self.replaces.update(dict(zip(self.rng, rng)))
|
||||||
|
self.rng = rng
|
||||||
|
|
||||||
|
# NOTE: needed for tensor cores
|
||||||
|
self.substitute()
|
||||||
|
|
||||||
|
self.maxarg = max([x.arg[0] for x in self.rng]) if len(self.rng) else 0
|
||||||
|
|
||||||
|
def substitute(self) -> UOp:
|
||||||
|
self.ast = graph_rewrite(self.ast.substitute(self.replaces), pm_flatten_range)
|
||||||
|
self.replaces = {}
|
||||||
|
return self.ast
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
self.substitute()
|
||||||
|
return RKernel(self.ast, self.opts)
|
||||||
|
|
||||||
|
# must be done earlier
|
||||||
|
def simplify_merge_adjacent(self): return
|
||||||
|
|
||||||
|
def apply_opt(self, opt:Opt, append_opt:bool=True) -> UOp|None:
|
||||||
|
if opt.op == OptOps.PADTO: raise KernelOptError("PAD is not supported yet. needs INVALID")
|
||||||
|
if opt.op == OptOps.SWAP: raise KernelOptError("SWAP is not supported yet")
|
||||||
|
return super().apply_opt(opt, append_opt)
|
||||||
|
|
||||||
|
def shift_to(self, axis:int, amount:int, new_type:AxisType, top:bool=False, insert_at:int|None=None):
|
||||||
|
old_sz = self.rng[axis].src[0].arg // amount
|
||||||
|
assert old_sz > 0, f"bad old_sz on {axis} {amount} {self.rng[axis]}"
|
||||||
|
|
||||||
|
self.maxarg += 1
|
||||||
|
new_rng = UOp.range(amount, self.maxarg, new_type)
|
||||||
|
|
||||||
|
if old_sz == 1:
|
||||||
|
self.replaces[self.rng[axis]] = new_rng
|
||||||
|
self.rng.insert(insert_at if insert_at is not None else len(self.rng), new_rng)
|
||||||
|
del self.rng[axis]
|
||||||
|
else:
|
||||||
|
replaced_rng = self.rng[axis].replace(src=(UOp.const(dtypes.int, old_sz),))
|
||||||
|
self.replaces[self.rng[axis]] = (new_rng * old_sz + replaced_rng) if top else (replaced_rng * amount + new_rng)
|
||||||
|
self.rng[axis] = replaced_rng
|
||||||
|
self.rng.insert(insert_at if insert_at is not None else len(self.rng), new_rng)
|
||||||
|
return new_rng
|
||||||
|
|
||||||
|
@property
|
||||||
|
def axis_types(self) -> list[AxisType]: return [x.arg[-1] for x in self.rng]
|
||||||
|
@property
|
||||||
|
def shape_len(self): return len(self.rng)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_shape(self) -> tuple[sint, ...]: return tuple([ssimplify(x.src[0]) for x in self.rng])
|
||||||
|
@property
|
||||||
|
def output_shape(self) -> tuple[sint, ...]:
|
||||||
|
if self.ast.src[0].op is not Ops.STORE: return ()
|
||||||
|
return tuple([ssimplify(x.src[0]) for x in self.ast.src[0].src[2:]])
|
||||||
|
|
||||||
|
def get_optimized_ast(self, name_override:str|None=None) -> UOp:
|
||||||
|
ret = self.substitute()
|
||||||
|
kernel_name = ret.arg.name if ret.arg is not None and ret.arg.name != "test" else self.name if name_override is None else name_override
|
||||||
|
rarg = KernelInfo(kernel_name, tuple(self.axis_types), self.dont_use_locals, tuple(self.applied_opts))
|
||||||
|
return ret.replace(arg=rarg)
|
||||||
|
|
||||||
|
# does nothing
|
||||||
|
@axis_types.setter
|
||||||
|
def axis_types(self, value): pass
|
||||||
|
|
||||||
|
def _apply_tc_opt(self, use_tensor_cores:int, axis:int, tc_select:int, opt_level:int) -> bool:
|
||||||
|
reduceops = [x for x in self.ast.toposort() if x.op is Ops.REDUCE]
|
||||||
|
if not len(reduceops): raise KernelOptError("no reduce ops for TensorCore")
|
||||||
|
reduceop = reduceops[0]
|
||||||
|
if use_tensor_cores and reduceop is not None and reduceop.arg is Ops.ADD:
|
||||||
|
mul = reduceop.src[0] if reduceop.src[0].op is not Ops.CAST else reduceop.src[0].src[0]
|
||||||
|
if mul.op is not Ops.MUL: return False
|
||||||
|
in0, in1 = mul.src
|
||||||
|
tensor_cores = self.opts.tensor_cores if tc_select == -1 else [self.opts.tensor_cores[tc_select]]
|
||||||
|
for tc in tensor_cores:
|
||||||
|
if tc.dtype_in == in0.dtype.scalar() and tc.dtype_in == in1.dtype.scalar() and tc.dtype_out == reduceop.dtype.scalar():
|
||||||
|
# early realize for TC
|
||||||
|
self.substitute()
|
||||||
|
|
||||||
|
# tensor cores have three ranges. X, Y, and REDUCE
|
||||||
|
in0_ranges = sorted([u for u in in0.ranges if u not in in1.ranges], key=lambda x: x.arg[0])
|
||||||
|
in1_ranges = sorted([u for u in in1.ranges if u not in in0.ranges], key=lambda x: x.arg[0])
|
||||||
|
red_ranges = sorted(reduceop.src[1:], key=lambda x: x.arg[0])
|
||||||
|
if DEBUG >= 3:
|
||||||
|
print(f"TC({axis}): {[(x.arg[0],x.vmax+1) for x in in0_ranges]}",
|
||||||
|
f"{[(x.arg[0],x.vmax+1) for x in in1_ranges]} {[(x.arg[0],x.vmax+1) for x in red_ranges]}")
|
||||||
|
if not len(in0_ranges) or not len(in1_ranges) or not len(red_ranges): return None
|
||||||
|
|
||||||
|
# pick ranges
|
||||||
|
# NOTE: why are in1 and in0 switched?
|
||||||
|
axis_choices = list(itertools.product(in1_ranges, in0_ranges, red_ranges))
|
||||||
|
if not (axis < len(axis_choices)): return None
|
||||||
|
axes = axis_choices[axis]
|
||||||
|
|
||||||
|
# do optimizations and save the ranges
|
||||||
|
try:
|
||||||
|
for i,a in enumerate(axes):
|
||||||
|
if a.src[0].divides(tc.dims[i]) is None:
|
||||||
|
self.apply_opt(Opt(OptOps.PADTO, self.rng.index(a), tc.dims[i]), append_opt=False) # PADTO might fail
|
||||||
|
except KernelOptError: continue
|
||||||
|
ne: list[UOp] = []
|
||||||
|
for opt in tc.opts:
|
||||||
|
ne.append(self.apply_opt(Opt({"u":OptOps.UPCAST, "l":OptOps.LOCAL}[opt[0]], axes[int(opt[1])].arg[0], 2), append_opt=False))
|
||||||
|
reduce_axis = [self.rng[i] for i in self.axes_of(AxisType.REDUCE)].index(axes[2])
|
||||||
|
for _, amt in tc.get_reduce_axes():
|
||||||
|
ne.append(self.apply_opt(Opt(OptOps.UNROLL, reduce_axis, amt), append_opt=False))
|
||||||
|
|
||||||
|
if use_tensor_cores != 2:
|
||||||
|
# fix the srcs
|
||||||
|
reduceop = [x for x in self.ast.toposort() if x.op is Ops.REDUCE][0]
|
||||||
|
tne = [x.replace(tag=1) for x in ne]
|
||||||
|
ret = reduceop.substitute(dict(zip(ne, tne)))
|
||||||
|
srcs = list((ret.src[0] if ret.src[0].op is not Ops.CAST else ret.src[0].src[0]).src)
|
||||||
|
srcs = [x.substitute(dict(zip(tne, [ne[i] for i in p]))) for x,p in zip(srcs, tc.permutes_for_shape_str(tc.base_shape_str()))]
|
||||||
|
|
||||||
|
# get reduce/upcast axes for the tensor cores
|
||||||
|
tc_reduce_axes = self.shape_str_to_axis([f"r{i}" for i in range(len(tc.get_reduce_axes()))])
|
||||||
|
base_upcast_axes = tuple([(s,2) for s in self.shape_str_to_axis(tc.base_upcast_axes())])
|
||||||
|
tc_upcast_axes = tuple([base_upcast_axes[:int(math.log2(tc.elements_per_thread[i]))] for i in range(3)])
|
||||||
|
|
||||||
|
# axes to range number (was done in lowerer)
|
||||||
|
tc_upcast_axes = tuple([tuple([(self.rng[a].arg[0], sz) for a,sz in v]) for v in tc_upcast_axes])
|
||||||
|
tc_reduce_axes = tuple([self.rng[a].arg[0] for a in tc_reduce_axes])
|
||||||
|
|
||||||
|
# construct the op
|
||||||
|
# TODO: remove tc_upcast_axes from the arg
|
||||||
|
wmma_arg = (str(tc), tc.dims, tc.dtype_in, tc.dtype_out, self.opts.device, tc.threads, tc_upcast_axes, tc_reduce_axes)
|
||||||
|
wmma = UOp(Ops.WMMA, dtype=tc.dtype_out.vec(tc.elements_per_thread[2]), src=(
|
||||||
|
UOp(Ops.CONTRACT, dtype=srcs[0].dtype.vec(tc.elements_per_thread[0]), src=(srcs[0],), arg=tc_upcast_axes[0], tag=1),
|
||||||
|
UOp(Ops.CONTRACT, dtype=srcs[1].dtype.vec(tc.elements_per_thread[1]), src=(srcs[1],), arg=tc_upcast_axes[1], tag=1),
|
||||||
|
UOp.const(tc.dtype_out.vec(tc.elements_per_thread[2]), 0.0)), arg=wmma_arg, tag=1)
|
||||||
|
tc_uop = UOp(Ops.UNROLL, tc.dtype_out, (wmma,), arg=tc_upcast_axes[2], tag=1)
|
||||||
|
|
||||||
|
# preserve extra reduces
|
||||||
|
reduce_ranges = [x for x in UOp.sink(*reduceop.src[1:]).toposort() if x.op is Ops.RANGE and x.arg[0] not in tc_reduce_axes]
|
||||||
|
if len(reduce_ranges): tc_uop = UOp(Ops.REDUCE, tc_uop.dtype, (tc_uop,)+tuple(reduce_ranges), Ops.ADD)
|
||||||
|
self.ast = self.ast.substitute({reduceop: tc_uop})
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def bufs_from_ast(ast:UOp, dname:str) -> list[Buffer]:
|
||||||
|
glbls = sorted([x for x in ast.parents if x.op is Ops.DEFINE_GLOBAL], key=lambda x: x.arg)
|
||||||
|
return [Buffer(dname, x.dtype.size, x.dtype.base) for x in glbls]
|
||||||
|
|
||||||
|
def apply_ropt(ast:UOp, renderer:Renderer):
|
||||||
|
k = RKernel(ast, opts=renderer)
|
||||||
|
if BEAM >= 1:
|
||||||
|
from tinygrad.codegen.opt.search import beam_search
|
||||||
|
kb = RKernel(ast, opts=renderer)
|
||||||
|
rawbufs = bufs_from_ast(ast, renderer.device)
|
||||||
|
k = beam_search(kb, rawbufs, BEAM.value, bool(getenv("BEAM_ESTIMATE", 1)))
|
||||||
|
elif ast.arg is not None: k.apply_opts(ast.arg.opts_to_apply)
|
||||||
|
return k.get_optimized_ast()
|
||||||
|
|
||||||
|
pm_postrange_opt = pm_flatten_range+PatternMatcher([
|
||||||
|
(UPat(Ops.SINK, name="ast"), lambda ctx,ast: apply_ropt(ast, ctx) if ast.arg is None or \
|
||||||
|
(ast.arg is not None and ast.arg.opts_to_apply is not None) else None),
|
||||||
])
|
])
|
||||||
|
|||||||
+1
-1
@@ -140,7 +140,7 @@ DONT_REALIZE_EXPAND, DONT_GROUP_REDUCES = ContextVar("DONT_REALIZE_EXPAND", 0),
|
|||||||
QUANTIZE, VALIDATE_WITH_CPU, DISABLE_FAST_IDIV = ContextVar("QUANTIZE", 0), ContextVar("VALIDATE_WITH_CPU", 0), ContextVar("DISABLE_FAST_IDIV", 0)
|
QUANTIZE, VALIDATE_WITH_CPU, DISABLE_FAST_IDIV = ContextVar("QUANTIZE", 0), ContextVar("VALIDATE_WITH_CPU", 0), ContextVar("DISABLE_FAST_IDIV", 0)
|
||||||
CORRECT_DIVMOD_FOLDING, FUSE_OPTIM = ContextVar("CORRECT_DIVMOD_FOLDING", 0), ContextVar("FUSE_OPTIM", 0)
|
CORRECT_DIVMOD_FOLDING, FUSE_OPTIM = ContextVar("CORRECT_DIVMOD_FOLDING", 0), ContextVar("FUSE_OPTIM", 0)
|
||||||
ALLOW_DEVICE_USAGE, MAX_BUFFER_SIZE, AMD_LLVM = ContextVar("ALLOW_DEVICE_USAGE", 1), ContextVar("MAX_BUFFER_SIZE", 0), ContextVar("AMD_LLVM", 1)
|
ALLOW_DEVICE_USAGE, MAX_BUFFER_SIZE, AMD_LLVM = ContextVar("ALLOW_DEVICE_USAGE", 1), ContextVar("MAX_BUFFER_SIZE", 0), ContextVar("AMD_LLVM", 1)
|
||||||
RANGEIFY, POSTOPT, FUSE_ATTENTION = ContextVar("RANGEIFY", 0), ContextVar("POSTOPT", 0), ContextVar("FUSE_ATTENTION", 0)
|
RANGEIFY, POSTOPT, FUSE_ATTENTION = ContextVar("RANGEIFY", 0), ContextVar("POSTOPT", 1), ContextVar("FUSE_ATTENTION", 0)
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Metadata:
|
class Metadata:
|
||||||
|
|||||||
Reference in New Issue
Block a user