forked from tinygrad/tinygrad
amd: fallback to llvm when comgr is not available (#15914)
This commit is contained in:
@@ -153,7 +153,7 @@ class TestDevVar(unittest.TestCase):
|
||||
self.assertEqual(DEV.target("CPU"), Target("CPU"))
|
||||
|
||||
def test_dev_arch_override(self):
|
||||
with Context(DEV="NULL:HIP:gfx1100"):
|
||||
with Context(DEV="NULL::gfx1100"):
|
||||
self.assertEqual(Device["NULL"].renderer.target.arch, "gfx1100")
|
||||
|
||||
class MockCompiler(Compiler):
|
||||
|
||||
@@ -722,7 +722,7 @@ class TestCfg(unittest.TestCase):
|
||||
gidx = UOp.special(1, "gidx0")
|
||||
sink = UOp.sink(out.base, lidx, gidx, arg=KernelInfo(name=name))
|
||||
return UOp(Ops.PROGRAM, src=(sink, UOp(Ops.DEVICE, arg="NULL"), UOp(Ops.LINEAR, src=tuple([UOp(Ops.INS, arg=x) for x in insts]))))
|
||||
with Context(DEV=f"NULL:HIP:{self.arch}"):
|
||||
with Context(DEV=f"NULL::{self.arch}"):
|
||||
out = Tensor.custom_kernel(Tensor.empty(1), fxn=fxn)[0]
|
||||
prg = out.schedule()[-1].lower().prg.p
|
||||
return amdgpu_cfg(prg.lib, self.arch)
|
||||
|
||||
+1
-1
@@ -293,7 +293,7 @@ class Compiled:
|
||||
f"{self.device}_{rn}=1 is deprecated, use DEV={self.device}:{rn} or {self.device}_CC={rn} instead"
|
||||
t = DEV.target(self.device.split(':')[0], **({"arch":self.arch} if self.arch else {}))
|
||||
return select_first_inited(select_by_name(self.renderers, self._renderer_name, t.renderer, f"{self.device} has no renderer {t.renderer!r}"),
|
||||
f"No renderer for {self.device} is available", self.cached_renderer, target=t)
|
||||
f"No renderer for {self.device} is available", self.cached_renderer, t)
|
||||
|
||||
def count(self) -> int:
|
||||
"""
|
||||
|
||||
+4
-4
@@ -133,13 +133,13 @@ def select_by_name(candidates:Sequence[T], get_name:Callable[...,str], query:str
|
||||
raise RuntimeError(err_msg + (f", did you mean: {m[0]!r}?" if (m:=difflib.get_close_matches(query, map(get_name, candidates))) else ""))
|
||||
return ret
|
||||
|
||||
def select_first_inited(candidates:Sequence[Callable[...,T]], err_msg:str, cache:dict|None=None, **kwargs):
|
||||
def select_first_inited(candidates:Sequence[Callable[...,T]], err_msg:str, cache:dict|None=None, *args):
|
||||
excs = []
|
||||
for typ in candidates:
|
||||
if cache is not None and typ in cache: return cache[typ]
|
||||
if cache is not None and (typ,) + args in cache: return cache[(typ,) + args]
|
||||
try:
|
||||
x = typ(**kwargs)
|
||||
if cache is not None: cache[typ] = x
|
||||
x = typ(*args)
|
||||
if cache is not None: cache[(typ,) + args] = x
|
||||
return x
|
||||
except Exception as e: excs.append(e)
|
||||
raise excs[0] if len(excs) == 1 else ExceptionGroup(err_msg + " is available", excs)
|
||||
|
||||
@@ -11,7 +11,7 @@ from tinygrad.runtime.autogen.amd.rdna3.ins import s_code_end # same encoding as
|
||||
from tinygrad.runtime.autogen.amd.cdna.ins import s_nop as s_nop_cdna
|
||||
|
||||
_arch_map = {"gfx9": "cdna", "gfx10": "rdna3", "gfx11": "rdna3", "gfx12": "rdna4"}
|
||||
def assemble_linear(ctx, prg:UOp, lin:UOp) -> bytes:
|
||||
def assemble_linear(prg:UOp, lin:UOp, arch:str) -> bytes:
|
||||
insts = [u.arg for u in lin.src]
|
||||
|
||||
# ** scan for max vgpr/sgpr/accvgpr
|
||||
@@ -41,7 +41,7 @@ def assemble_linear(ctx, prg:UOp, lin:UOp) -> bytes:
|
||||
elif u.op is Ops.DEFINE_LOCAL: lds_size += u.ptrdtype.size * u.ptrdtype.base.itemsize
|
||||
elif u.op is Ops.SPECIAL and u.arg.startswith("gidx"): gids.add(int(u.arg[-1]))
|
||||
code_bytes = b"".join(inst.to_bytes() for inst in insts)
|
||||
arch = next(v for k, v in _arch_map.items() if ctx.target.arch.startswith(k))
|
||||
arch = next(v for k, v in _arch_map.items() if arch.startswith(k))
|
||||
is_cdna, is_rdna4 = arch == "cdna", arch == "rdna4"
|
||||
|
||||
# ** pad text to ISA alignment
|
||||
|
||||
@@ -473,10 +473,10 @@ class HIPRenderer(CStyleLanguage):
|
||||
def is_cdna(arch): return arch.split(":")[0] in {"gfx942", "gfx950"}
|
||||
@staticmethod
|
||||
def is_cdna4(arch): return arch.split(":")[0] == "gfx950"
|
||||
def __init__(self, target:Target): # gfx942 => MI300, gfx1100 => RX 7900, gfx1201 => RX 9700
|
||||
def __init__(self, target:Target, use_hipcc=False): # gfx942 => MI300, gfx1100 => RX 7900, gfx1201 => RX 9700
|
||||
super().__init__(target)
|
||||
from tinygrad.runtime.support.compiler_amd import HIPCompiler
|
||||
self.compiler, self.tensor_cores = HIPCompiler(target.arch), tc.get_amd(target.arch)
|
||||
from tinygrad.runtime.support.compiler_amd import HIPCompiler, HIPCCCompiler
|
||||
self.compiler, self.tensor_cores = (HIPCCCompiler if use_hipcc else HIPCompiler)(target.arch), tc.get_amd(target.arch)
|
||||
if not self.is_cdna4(target.arch): self.extra_matcher += pm_manual_bf16_cast + extra_pm
|
||||
if self.is_cdna(target.arch):
|
||||
self.string_rewrite = PatternMatcher([
|
||||
@@ -512,7 +512,7 @@ class HIPRenderer(CStyleLanguage):
|
||||
|
||||
def asm(self, prg:UOp, lin:UOp) -> bytes:
|
||||
from tinygrad.renderer.amd.elf import assemble_linear
|
||||
return assemble_linear(self, prg, lin)
|
||||
return assemble_linear(prg, lin, self.target.arch)
|
||||
|
||||
def render_vector_prefix(self, dtype:DType) -> str:
|
||||
vec, scal = self.render_dtype(dtype), self.render_dtype(dtype.scalar())
|
||||
@@ -560,10 +560,7 @@ class HIPRenderer(CStyleLanguage):
|
||||
return super().render_kernel(function_name, kernel, bufs, uops, prefix)
|
||||
|
||||
class HIPCCRenderer(HIPRenderer):
|
||||
def __init__(self, target:Target):
|
||||
super().__init__(target)
|
||||
from tinygrad.runtime.support.compiler_amd import HIPCCCompiler
|
||||
self.compiler = HIPCCCompiler(target.arch)
|
||||
def __init__(self, target:Target): super().__init__(target, use_hipcc=True)
|
||||
|
||||
class QCOMCLRenderer(OpenCLRenderer):
|
||||
def __init__(self, target:Target):
|
||||
|
||||
@@ -238,7 +238,9 @@ class AMDLLVMRenderer(LLVMRenderer):
|
||||
(UPat(Ops.LOG2, dtype=dtypes.double, src=(UPat.var("d"),)), xlog2),
|
||||
(UPat(Ops.EXP2, dtype=dtypes.double, src=(UPat.var("d"),)), xexp2),
|
||||
])
|
||||
def asm(self, prg: UOp, lin: UOp) -> bytes: return HIPRenderer(self.target).asm(prg, lin)
|
||||
def asm(self, prg: UOp, lin: UOp) -> bytes:
|
||||
from tinygrad.renderer.amd.elf import assemble_linear
|
||||
return assemble_linear(prg, lin, self.target.arch)
|
||||
def render(self, uops: list[UOp]) -> str:
|
||||
prefix = ["""define i8 @f32_to_fp8(float %val, i1 %is_bf8) {
|
||||
entry: %ival = bitcast float %val to i32\n %exp = and i32 %ival, 2139095040\n %is_special = icmp eq i32 %exp, 2139095040
|
||||
|
||||
@@ -6,7 +6,7 @@ from tinygrad.renderer.cstyle import CUDARenderer, OpenCLRenderer
|
||||
from tinygrad.uop.ops import GroupOp, Ops, UOp, PatternMatcher, UPat, range_str
|
||||
from tinygrad.runtime.autogen import mesa
|
||||
from tinygrad.runtime.support.c import POINTER
|
||||
import base64, ctypes, ctypes.util, struct, functools, inspect, contextlib, itertools
|
||||
import base64, ctypes, ctypes.util, struct, functools, inspect, itertools
|
||||
|
||||
def g(s:str): return getattr(mesa, s)
|
||||
def nsrc(d:mesa.nir_def) -> mesa.nir_src: return mesa.nir_src(ssa=ctypes.pointer(d))
|
||||
@@ -169,9 +169,10 @@ class NIRRenderer(Renderer):
|
||||
self.compiler = fromimport("tinygrad.runtime.support.compiler_mesa", self.__class__.__name__.replace("Renderer", "Compiler"))(target.arch)
|
||||
if hasattr(self.compiler, "nir_options"): self.nir_options = self.compiler.nir_options
|
||||
mesa.glsl_type_singleton_init_or_ref()
|
||||
self._deinit_types = True
|
||||
|
||||
def __del__(self):
|
||||
with contextlib.suppress(AttributeError): mesa.glsl_type_singleton_decref()
|
||||
if getattr(self, "_deinit_types", False): mesa.glsl_type_singleton_decref()
|
||||
|
||||
def param(self, b:mesa.nir_builder, x, sz:int) -> mesa.nir_def: raise NotImplementedError("needs param")
|
||||
def prerender(self, uops:list[UOp]):
|
||||
|
||||
@@ -3,14 +3,18 @@ from tinygrad.device import Compiled, Allocator
|
||||
from tinygrad.engine.jit import MultiGraphRunner
|
||||
from tinygrad.renderer import Renderer, cstyle, nir, ptx, llvmir, wgsl
|
||||
from tinygrad.renderer.cstyle import CStyleLanguage
|
||||
from tinygrad.uop.ops import Ops
|
||||
from tinygrad.helpers import cpu_profile, getenv, NULL_ALLOW_COPYOUT
|
||||
from tinygrad.uop.ops import UOp, Ops
|
||||
from tinygrad.helpers import cpu_profile, getenv, dedup, NULL_ALLOW_COPYOUT
|
||||
|
||||
class NullRenderer(CStyleLanguage):
|
||||
has_local = False
|
||||
float4 = "float4"
|
||||
barrier = "// BARRIER"
|
||||
code_for_op = {**CStyleLanguage.code_for_op, Ops.THREEFRY: lambda a,b,dtype: f"threefry({a},{b})", Ops.MAX: lambda a,b,dtype: f"max({a},{b})"}
|
||||
def asm(self, prg: UOp, lin: UOp) -> bytes:
|
||||
assert self.target.arch.startswith("gfx"), "only amd supports assembly"
|
||||
from tinygrad.renderer.amd.elf import assemble_linear
|
||||
return assemble_linear(prg, lin, self.target.arch)
|
||||
|
||||
class NullProgram:
|
||||
def __init__(self, device:str, name:str, lib:bytes, *args, **kwargs): self.device, self.name = device, name
|
||||
@@ -35,4 +39,4 @@ class NullDevice(Compiled):
|
||||
"EMULATE is deprecated, use DEV=NULL:HIP:"+{"AMD":"gfx1100", "AMD_RDNA4":"gfx1201", "AMD_CDNA4":"gfx950"}.get(emu, "<arch>")
|
||||
renderers = [NullRenderer] + [r for m in [cstyle, nir, ptx, llvmir, wgsl] for r in m.__dict__.values()
|
||||
if inspect.isclass(r) and issubclass(r, Renderer)]
|
||||
super().__init__(device, NullAllocator(self), renderers, functools.partial(NullProgram, device), NullGraph)
|
||||
super().__init__(device, NullAllocator(self), dedup(renderers), functools.partial(NullProgram, device), NullGraph)
|
||||
|
||||
@@ -112,7 +112,7 @@ class DLL(ctypes.CDLL):
|
||||
if f.read(4) == b'\x7FELF': return str(l)
|
||||
|
||||
def __init__(self, nm:str, paths:str|list[str], extra_paths=[], emsg="", **kwargs):
|
||||
self.nm, self.emsg = nm, emsg
|
||||
self.nm, self.emsg = nm, emsg or f"try setting {nm.upper()+'_PATH'}?"
|
||||
if (path:= DLL.findlib(nm, paths if isinstance(paths, list) else [paths], extra_paths if isinstance(extra_paths, list) else [extra_paths])):
|
||||
if DEBUG >= 3: print(f"loading {nm} from {path}")
|
||||
try:
|
||||
@@ -135,6 +135,5 @@ class DLL(ctypes.CDLL):
|
||||
return wrap
|
||||
|
||||
def __getattr__(self, nm):
|
||||
if self.nm not in self._loaded_:
|
||||
raise AttributeError(f"failed to load library {self.nm}: " + (self.emsg or f"try setting {self.nm.upper()+'_PATH'}?"))
|
||||
if self.nm not in self._loaded_: raise AttributeError(f"failed to load library {self.nm}: {self.emsg}")
|
||||
return super().__getattr__(nm)
|
||||
|
||||
@@ -92,6 +92,7 @@ def compile_hip(prg:str, arch="gfx1100", asm=False) -> bytes:
|
||||
|
||||
class HIPCompiler(Compiler):
|
||||
def __init__(self, arch:str):
|
||||
assert comgr.dll.nm in c.DLL._loaded_, f"comgr not available: {comgr.dll.emsg}"
|
||||
self.arch = arch
|
||||
super().__init__(f"compile_hip_{self.arch}")
|
||||
def compile(self, src:str) -> bytes:
|
||||
|
||||
Reference in New Issue
Block a user