mirror of
https://github.com/tinygrad/tinygrad.git
synced 2026-08-29 13:56:06 +00:00
structuring
This commit is contained in:
+64
-11
@@ -2,6 +2,7 @@
|
||||
# mypy: ignore-errors
|
||||
from __future__ import annotations
|
||||
import ctypes
|
||||
from tinygrad.helpers import DEBUG
|
||||
from extra.assembly.amd.dsl import Inst, unwrap, FLOAT_ENC, MASK32, MASK64, _f32, _i32, _sext, _f16, _i16, _f64, _i64
|
||||
from extra.assembly.amd.pcode import Reg
|
||||
from extra.assembly.amd.asm import detect_format
|
||||
@@ -449,34 +450,87 @@ from extra.assembly.amd.sqtt import WAVESTART, WAVEEND, IMMEDIATE, VALUINST, ALU
|
||||
# InstSkip = SIMM16[6:4]
|
||||
# InstID1 = SIMM16[10:7]
|
||||
|
||||
class VQueueItem:
|
||||
def __init__(self, inst, deps):
|
||||
self.inst = inst
|
||||
self.deps = deps
|
||||
# TODO: this should track through the phases of VQueue
|
||||
self.cycles = 7
|
||||
def tick(self):
|
||||
if any(not d.finished() for d in self.deps): return
|
||||
self.cycles -= 1
|
||||
def finished(self):
|
||||
return self.cycles <= 0
|
||||
|
||||
def _get_src_vgprs(inst: Inst) -> list[int]:
|
||||
if isinstance(inst, VOP1): return [inst.src0 - 256] if inst.src0 >= 256 else []
|
||||
if isinstance(inst, VOP2): return ([inst.src0 - 256] if inst.src0 >= 256 else []) + [inst.vsrc1]
|
||||
if isinstance(inst, VOP3): return [s - 256 for s in [inst.src0, inst.src1, getattr(inst, 'src2', None)] if s is not None and s >= 256]
|
||||
return []
|
||||
|
||||
class SQTTState:
|
||||
def __init__(self, wave_id: int = 0, simd: int = 0, cu: int = 0):
|
||||
self.wave_id, self.simd, self.cu = wave_id, simd, cu
|
||||
self.cycle = 0
|
||||
self.packets = []
|
||||
self.inst_count = 0
|
||||
self.last_inst = None
|
||||
self.vqueue:list[VQueueItem] = []
|
||||
self.vgpr_pends = {}
|
||||
self.delay_alu = 0
|
||||
|
||||
def emit(self, pkt_class, **kwargs):
|
||||
self.packets.append(pkt_class(_time=self.cycle, **kwargs))
|
||||
|
||||
def tick(self):
|
||||
for q in self.vqueue: q.tick()
|
||||
# if this instruction is finished, mark it as finished
|
||||
if len(self.vqueue) and self.vqueue[0].finished():
|
||||
self.emit(ALUEXEC, src=AluSrc.VALU)
|
||||
self.vqueue.pop(0)
|
||||
self.cycle += 1
|
||||
|
||||
def process_instruction(self, inst: Inst):
|
||||
if inst.op == SOPPOp.S_NOP:
|
||||
if DEBUG >= 2: print(inst)
|
||||
if isinstance(inst, SOPP) and inst.op == SOPPOp.S_DELAY_ALU:
|
||||
# delay alu isn't a dispatch
|
||||
self.delay_alu = inst.simm16
|
||||
return
|
||||
elif isinstance(inst, SOPP) and inst.op == SOPPOp.S_NOP:
|
||||
# this repros with s_nop(0), s_nop(7)
|
||||
in_range = (SNOP_EXTRA_DELAY_MIN <= inst.simm16 <= SNOP_EXTRA_DELAY_MAX and self.inst_count > 0)
|
||||
for _ in range(inst.simm16 + (SNOP_EXTRA_DELAY_CYCLES if in_range else 0)): self.tick()
|
||||
# why does this happen?
|
||||
# TODO: i think the 4 cycles is a generic stall, it's also seen in non indep valu chains
|
||||
in_range = (SNOP_EXTRA_DELAY_MIN <= inst.simm16 <= SNOP_EXTRA_DELAY_MAX and self.last_inst is not None)
|
||||
cycles = inst.simm16
|
||||
# 2 extra cycles
|
||||
if isinstance(self.last_inst, (VOP1, VOP2, VOP3)): cycles += 2
|
||||
if in_range: cycles += SNOP_EXTRA_DELAY_CYCLES
|
||||
for _ in range(cycles): self.tick()
|
||||
self.emit(IMMEDIATE, wave=self.wave_id)
|
||||
self.tick()
|
||||
self.inst_count += 1
|
||||
elif isinstance(inst, SOPP) and inst.op == SOPPOp.S_ENDPGM:
|
||||
while len(self.vqueue): self.tick()
|
||||
self.emit(WAVEEND, wave=self.wave_id, simd=self.simd, cu_lo=self.cu & 0x7, flag7=self.cu >> 3)
|
||||
elif isinstance(inst, (VOP1, VOP2, VOP3)):
|
||||
# delay_alu delays the dispatch
|
||||
if self.delay_alu and len(self.vqueue):
|
||||
# TODO: support other delay_alus
|
||||
while self.vqueue[-1].cycles > 2: self.tick()
|
||||
# TODO: if vqueue is full, there's a delay on enqueuing
|
||||
deps = []
|
||||
for src in _get_src_vgprs(inst):
|
||||
if src in self.vgpr_pends:
|
||||
deps.append(self.vgpr_pends[src])
|
||||
self.vqueue.append(VQueueItem(inst, deps))
|
||||
self.vgpr_pends[inst.vdst] = self.vqueue[-1]
|
||||
self.emit(VALUINST, wave=self.wave_id)
|
||||
|
||||
# we can only issue one instruction per cycle
|
||||
self.tick()
|
||||
self.last_inst = inst
|
||||
self.delay_alu = 0
|
||||
|
||||
def emit_wavestart(self):
|
||||
self.emit(WAVESTART, wave=self.wave_id, simd=self.simd, cu_lo=self.cu & 0x7, flag7=self.cu >> 3)
|
||||
for _ in range(WAVESTART_TO_INST_CYCLES): self.tick()
|
||||
|
||||
def finalize(self):
|
||||
self.emit(WAVEEND, wave=self.wave_id, simd=self.simd, cu_lo=self.cu & 0x7, flag7=self.cu >> 3)
|
||||
"""
|
||||
|
||||
class SQTTState:
|
||||
@@ -617,8 +671,7 @@ def exec_wave(program: Program, st: WaveState, lds: LDSMem, n_lanes: int, trace:
|
||||
result = step_wave(program, st, lds, n_lanes, trace)
|
||||
if result == -1: break
|
||||
if result == -2: return -2
|
||||
if trace is not None:
|
||||
trace.finalize()
|
||||
#if trace is not None: trace.finalize()
|
||||
return 0
|
||||
|
||||
def exec_workgroup(program: Program, workgroup_id: tuple[int, int, int], local_size: tuple[int, int, int], args_ptr: int,
|
||||
|
||||
@@ -2876,6 +2876,18 @@ class TestCustom(SQTTCompareTestBase):
|
||||
s_nop(0),
|
||||
], nops=0)
|
||||
|
||||
def test_nop_after_v(self, delay=0):
|
||||
self._run_and_compare([
|
||||
v_mov_b32_e32(v[0], 1.0),
|
||||
s_nop(delay),
|
||||
v_mov_b32_e32(v[1], 1.0),
|
||||
s_nop(0),
|
||||
], nops=0)
|
||||
|
||||
def test_nop_after_v_2(self): self.test_nop_after_v(2)
|
||||
def test_nop_after_v_4(self): self.test_nop_after_v(4)
|
||||
def test_nop_after_v_8(self): self.test_nop_after_v(8)
|
||||
|
||||
def test_long_nop_after_v(self):
|
||||
self._run_and_compare([
|
||||
v_mov_b32_e32(v[0], 1.0),
|
||||
@@ -2883,11 +2895,11 @@ class TestCustom(SQTTCompareTestBase):
|
||||
], nops=0)
|
||||
|
||||
def test_long_nop(self):
|
||||
self._run_and_compare([
|
||||
self._run_and_compare(ins:=[
|
||||
s_nop(0),
|
||||
s_nop(0),
|
||||
s_nop(7),
|
||||
s_nop(18), # 18 actually delays longer that 19
|
||||
], nops=0)
|
||||
print(ins)
|
||||
|
||||
def test_one_nop(self):
|
||||
self._run_and_compare([
|
||||
@@ -2977,11 +2989,22 @@ class TestCustom(SQTTCompareTestBase):
|
||||
s_nop(0),
|
||||
], nops=0, emu=False)
|
||||
|
||||
def test_long_chain(self):
|
||||
def test_long_chain(self, chain_length=30, nops=0):
|
||||
# this isn't modelled correctly
|
||||
# the VGPRs are in a quque that eventually stalls
|
||||
ins = [v_mov_b32_e32(v[0], 1.0)]
|
||||
for i in range(chain_length):
|
||||
ins.append(v_mov_b32_e32(v[i+1], v[i]))
|
||||
self._run_and_compare(ins, nops=nops)
|
||||
|
||||
def test_short_chain(self): self.test_long_chain(1, nops=16)
|
||||
def test_med_chain(self): self.test_long_chain(2, nops=16)
|
||||
|
||||
def test_long_chain_indep(self):
|
||||
# this isn't modelled correctly
|
||||
ins = [v_mov_b32_e32(v[0], 1.0)]
|
||||
for i in range(30):
|
||||
ins.append(v_mov_b32_e32(v[i+1], v[i]))
|
||||
ins.append(v_mov_b32_e32(v[i+1], 1.0))
|
||||
self._run_and_compare(ins, nops=0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user